Перейти к содержанию

Зачем нужен TypeScript

У TypeScript есть две основные цели:

  • Предоставить возможность опционального описания типов в JavaScript
  • Предоставить возможность использовать сейчас улучшения, запланированные в будущих версиях JavaScript, посредством полифиллов.

Мотивация для достижения этих целей описана ниже.

Система типов TypeScript

Возможно, вы спросите "Зачем добавлять типы в JavaScript?"

Типизация позволяет улучшить качество и понимаемость кода. Большие команды (Google, Microsoft, Facebook) постоянно приходят к такому выводу. А именно:

  • Типы повышают вашу гибкость при рефакторинге. Пусть лучше компилятор поймает ошибку, чем что-то сломается в рантайме
  • Типы - это один из лучших, доступных вам видов документации. Сигнатура функции - это теорема, а тело функции - её доказательство.

Однако, типы могут быть излишне требовательными. TypeScript очень заботится о том, чтобы входной порог был как можно ниже. А именно:

Ваш JavaScript - это TypeScript

TypeScript обеспечивает для вашего кода на JavaScript типобезопасность во время компиляции. Учитывая его название, это неудивительно. Большое преимущество в том, что типы полностью опциональны. Ваш файл .js с кодом на JavaScript может быть переименован в файл .ts и TypeScript всё еще вернёт вам валидный .js, эквивалентный оригинальному файлу JavaScript. TypeScript намеренно является строгой надстройкой над JavaScript с дополнительной проверкой Типов.

Типы могут быть Неявными

TypeScript будет пытаться вывести как можно больше информации о типах, чтобы предоставить вам типобезопасность с минимальными потерями продуктивности при написании кода. Например, в следующем примере TypeScript узнает, что тип foo будет number и выдаст ошибку на второй строке:

1
2
3
4
var foo = 123;
foo = '456'; // Error: cannot assign `string` to `number`

// foo это число или строка?

Такой вывод типов имеет весомые основания. Если вы делаете как в примере выше, то вы не можете быть уверены, что далее в коде foo будет number или string. Такие вопросы часто возникают в больших многофайловых кодовых базах. Позже мы рассмотрим правила вывода типов более подробно.

Типы могут быть Явными

Как мы уже сказали, TypeScript делает выводы максимально безопасно. Тем не менее, вы можете использовать аннотации, чтобы:

  1. Помочь компилятору и, что более важно, документировать код для разработчика, который будет читать код после вас (им может стать будущий вы!).
  2. Убедиться, что то, что видит компилятор и то, что вы задумали - это одно и то же. Таким образом, ваше понимание кода совпадает с алгоритмическим анализом кода (выполняемым компилятором).

TypeScript использует постфиксную аннотацию типов, популярную в других опционально аннотируемых языках (например, ActionScript и F#).

1
var foo: number = 123;

Так что, если вы ошибётесь, компилятор выдаст ошибку:

1
var foo: number = '123'; // Error: cannot assign a `string` to a `number`

Мы подробно обсудим весь синтаксис аннотаций, поддерживаемый TypeScript в другой главе.

Типы являются структурными

В некоторых языках (особенно в номинально типизированных) статическая типизация приводит к ненужным церемониям, потому что даже если вы знаете, что код будет работать, семантика языка заставляет вас всюду копировать сущности. Поэтому такие вещи, как автомаппер для C# жизненно необходимы для C#. В TypeScript типы являются структурными, потому что мы действительно хотим, чтобы для разработчиков JavaScript это было просто и с минимумом когнитивной нагрузки. Это значит, что утиная типизация - это языковая конструкция первого класса. Рассмотрим следующий пример. Функция iTakePoint2D примет всё, что содержит элементы, которые она ожидает (x and y):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
interface Point2D {
    x: number;
    y: number;
}
interface Point3D {
    x: number;
    y: number;
    z: number;
}
var point2D: Point2D = { x: 0, y: 10 };
var point3D: Point3D = { x: 0, y: 10, z: 20 };
function iTakePoint2D(point: Point2D) {
    /* сделать что-нибудь */
}

iTakePoint2D(point2D); // полное совпадение - ок
iTakePoint2D(point3D); // дополнительная информация - okay
iTakePoint2D({ x: 0 }); // Ошибка: не хватает `y`

Ошибки типов не мешают выводу JavaScript

Чтобы вам было проще мигрировать с JavaScript, по умолчанию TypeScript выдаст настолько валидный JavaScript, насколько сможет, даже если есть ошибки компиляции. Например:

1
2
var foo = 123;
foo = '456'; // Error: cannot assign a `string` to a `number`

выдаст следующий js:

1
2
var foo = 123;
foo = '456';

Так что вы можете инкрементально обновлять ваш код с JavaScript на TypeScript. В этом важное отличие от того, как работают многие другие компиляторы и это еще одна причина перейти на TypeScript.

Типы могут быть фоновыми

Основной целью дизайна TypeScript была возможность просто и безопасно использовать существующие библиотеки JavaScript. TypeScript реализует это с помощью декларации. TypeScript предоставляет вам широкий спектр того, насколько мало или много усилий вы хотите потратить на декларации; чем больше вы потратите, тем более типобезопасный и понятный код вы получите. Заметьте, что определения для большинства популярных библиотек JavaScript уже были написаны для вас сообществом DefinitelyTyped, поэтому в большинстве случаев либо:

  1. Файл дефиниций уже существует.
  2. Либо, как минимум, у вас есть большой список уже готовых проверенных шаблонов деклараций TypeScript

В качестве быстрого примера того, как вы можете написать свой файл деклараций, рассмотрим простой пример jquery. По умолчанию (что и ожидается от хорошего кода JS) TypeScript ожидает объявления (т.е. использования где-нибудь var) перед тем как использовать переменную:

1
$('.awesome').show(); // Ошибка: не могу найти `$`

Для исправления вы можете рассказать TypeScript, что тут есть что-то под названием $:

1
2
declare var $: any;
$('.awesome').show(); // Окей!

Если хотите защититься от ошибок, то можно предоставить больше информации, опираясь на это определение:

1
2
3
4
5
declare var $: {
    (selector: string): any;
};
$('.awesome').show(); // Окей!
$(123).show(); // Ошибка: селектор должен быть строкой

Мы обсудим подробности создания определений TypeScript для существующего JavaScript позже, когда вы больше узнаете о TypeScript (такие вещи как interface и any).

Будущее JavaScript => Сейчас

TypeScript предоставляет множество особенностей, запланированных в ES6 и в текущих движках JavaScript (которые поддерживают только ES5 и др.). Команда TypeScript активно добавляет эти фичи и их список со временем будет только расти, о чем мы расскажем в соответствующем разделе. В качестве образца здесь приведен пример класса:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Point {
    constructor(public x: number, public y: number) {}
    add(point: Point) {
        return new Point(
            this.x + point.x,
            this.y + point.y
        );
    }
}

var p1 = new Point(0, 10);
var p2 = new Point(10, 20);
var p3 = p1.add(p2); // { x: 10, y: 30 }

и любимая стрелочная функция:

1
var inc = (x) => x + 1;

Резюме

В этом разделе мы рассказали о движущей силе и дизайне TypeScript. Разобравшись с этим, мы можем погружаться в мельчайшие подробности TypeScript.

Комментарии