У TypeScript есть две основные цели:
- Предоставить возможность опционального описания типов в JavaScript
- Предоставить возможность использовать сейчас улучшения запланированные в будущих версиях JavaScript, посредством полифилов.
Мотивация для достижения этих целей описана ниже.
Возможно, вы спросите "Зачем добавлять типы в JavaScript?"
Типизация позволяет улучшить качество и понимаемость кода. Большие команды (Google, Microsoft, Facebook) постоянно приходят к такому выводу. А именно:
- Типы повышают вашу гибкость при рефакторинге. Пусть лучше компилятор поймает ошибку, чем что-то сломается в рантайме
- Типы это один из лучших доступных вам видов документации. Сигнатура функции - это теорема, а тело функции - её доказательство.
Однако, типы могут быть излишне требовательными. TypeScript очень заботится о том, чтобы входной порог был как можно ниже. А именно:
TypeScript обеспечивает для вашего кода на JavaScript типобезопасность во время компиляции. Учитывая его название, это не удивительно. Большое преимущество в том, что типы полностью опциональны. Ваш файл .js
с кодом на JavaScript может быть переименован в файл .ts
и TypeScript всё еще вернёт вам валидный .js
, эквивалентный оригинальному файлу JavaScript. TypeScript намеренно является строгой надстройкой над JavaScript с дополнительной проверкой Типов.
TypeScript будет пытаться вывести как можно больше информации о типах, чтобы предоставить вам типобезопасность с минимальными потерями продуктивности при написании кода. Например, в следующем примере TypeScript узнает, что тип foo будет number
и выдаст ошибку на второй строке:
var foo = 123;
foo = '456'; // Error: cannot assign `string` to `number`
// foo это число или строка?
Такой вывод типов имеет весомые основания. Если вы делаете как в примере выше, то вы не можете быть уверены, что далее в коде foo
будет number
или string
. Такие вопросы часто возникают в больших многофайловых кодовых базах. Позже мы рассмотрим правила вывода типов более подробно.
Как мы уже сказали, TypeScript делает выводы максимально безопасно. Тем не менее, вы можете использовать аннотации, чтобы:
- Помочь компилятору и, что более важно, документировать код для разработчика, который будет читать код после вас (им может стать будущий вы!).
- Убедиться, что то, что видет компилятор и то, что вы задумали - это одно и то же. Таким образом ваше понимание кода совпадает с алгоритмическим анализом кода (выполняемым компилятором).
TypeScript использует постфиксную аннотацию типов, популярную в других опционально аннотируемых языках (например, ActionScript и F#).
var foo: number = 123;
Так что если вы ошибётесь, компилятор выдаст ошибку:
var foo: number = '123'; // Error: cannot assign a `string` to a `number`
Мы подробно обсудим весь синтаксис аннотаций, поддерживаемый TypeScript в другой главе.
В некоторых языках (особенно в номинально типизированных) статическая типизация приводит к ненужным церемониям, потому что даже если вы знаете, что код будет работать, семантика языка заставляет вас всюду копировать сущности. Поэтому такие вещи, как автомаппер для C# жизненно необходимы для C#. В TypeScript типы являются структурными, потому что мы действительно хотим, чтобы для разработчиков JavaScript это было просто и с минимумом когнитивной нагрузки. Это значит, что утиная типизация - это языковая конструкция первого класса. Рассмотрим следующий пример. Функция iTakePoint2D
примет всё, что содержит элементы, которые она ожидает (x
and y
):
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, по умолчанию TypeScript выдаст настолько валидный JavaScript, насколько сможет, даже если есть ошибки компиляции. Например:
var foo = 123;
foo = '456'; // Error: cannot assign a `string` to a `number`
выдаст следующий js:
var foo = 123;
foo = '456';
Так что вы можете инкрементально обновлять ваш код с JavaScript на TypeScript. В этом важное отличие от того, как работают многие другие компиляторы и это еще одна причина перейти на TypeScript.
Основной целью дизайна TypeScript была возможность просто и безопасно использовать существующие библиотеки JavaScript. TypeScript реализует это с помощью декларации. TypeScript предоставляет вам широкий спектр того, насколько мало или много усилий вы хотите потратить на декларации; чем больше вы потратите, тем более типобезопасный и понятный код вы получите. Заметьте, что определения для большинства популярных библиотек JavaScript уже были написаны для вас сообществом DefinitelyTyped, поэтому в большинстве случаев либо:
- Файл дефиниций уже существует.
- Либо, как минимум, у вас есть большой список уже готовых проверенных шаблонов деклараций TypeScript
В качестве быстрого примера того, как вы можете написать свой файл деклараций, рассмотрим простой пример jquery. По умолчанию (что и ожидается от хорошего кода JS) TypeScript ожидает объявления (т.е. использования где-нибудь var
) перед тем как использовать переменную:
$('.awesome').show(); // Ошибка: не могу найти `$`
Для исправления вы можете рассказать TypeScript, что тут есть что-то под названием $
:
declare var $: any;
$('.awesome').show(); // Окей!
Если хотите защититься от ошибок, то можно предоставить больше информации, опираясь на это определение:
declare var $: {
(selector:string): any;
};
$('.awesome').show(); // Окей!
$(123).show(); // Ошибка: селектор должен быть строкой
Мы обсудим подробности создания определений TypeScript для существующего JavaScript позже, когда вы больше узнаете о TypeScript (такие вещи как interface
и any
).
TypeScript предоставляет множество особенностей, запланированных в ES6 и в текущих движках JavaScript (которые поддерживают только ES5 и др.). Команда TypeScript активно добавляет эти фичи и их список со временем будет только расти, о чем мы расскажем в соответствующем разделе. В качестве образца здесь приведен пример класса:
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 }
и любимая стрелочная функция:
var inc = x => x+1;
В этом разделе мы рассказали о движущей силе и дизайне TypeScript. Разобравшись с этим, мы можем погружаться в мельчайшие подробности TypeScript.
[](Interfaces are open ended) [](Правила вывода типов) [](Cover all the annotations) [](Cover all ambients : also that there are no runtime enforcement) [](.ts vs. .d.ts)