Введение
TypeScript — это сильно типизированный, объектно-ориентированный и компилируемый open-source язык, разработанный и поддерживаемый компанией Microsoft. Он был создан в целях привнесения статических типов в современный JavaScript. Компилятор TypeScript читает код TypeScript с объявлениями и аннотациями типов и выдает чистый и читаемый JavaScript-код с преобразованными и удаленными конструкциями. Этот код запускается в любой среде исполнения ECMAScript, например, в браузерах и Node.js.
В этой статье мы ознакомимся с несколькими функциями, добавленными в TypeScript в различных версиях 3.x.
Версии TypeScript:
- 3.0, выпущенная в июле 2018
- 3.1, выпущенная в сентябре 2018
- 3.2, выпущенная в ноябре 2018
- 3.3, выпущенная в январе 2019
- 3.4, выпущенная в марте 2019
Разберем новые функции в хронологическом порядке:
Ссылки на проект
Эта новая концепция появилась в TypeScript 3.0. С ее помощью можно установить один проект TypeScript в зависимость от другого проекта TypeScript с помощью ссылки на файлы tsconfig.json
, что увеличивает модульность написания кода. TypeScript 3.0 также предоставляет новый режим для tsc, флаг --build
. Он работает с ссылками на проекты, ускоряя сборку.
Новый тип unknown
В TypeScript 3.0 также представлен новый тип верхнего уровня unknown
. Любой элемент может быть обозначен типом unknown
, однако этот тип нельзя назначить для других элементов, кроме самого себя и any
, без утверждения типа или сужения потока управления.
Поддержка defaultProps в JSX
Для разработки React на JSX TypeScript 3.0 предоставляет поддержку нового типа в пространстве имен JSX
под названием LibraryManagedAttributes
. Это вспомогательный тип, который определяет изменения в prop-типах компонентов перед использованием, что позволяет вносить изменения в props и mappings.
export interface Props {
name: string;
}
export class Greet extends React.Component<Props> {
render() {
const { name } = this.props;
return <div>Hello {name.toUpperCase()}!</div>;
}
static defaultProps = { name: "world"};
}
// Проверка типов! Тип assertions не нужен!
let el = <Greet />
Однако стоит отметить, что свойства по умолчанию выводятся из типа property defaultProps
. Поэтому при добавлении явной аннотации типа компилятор не сможет идентифицировать свойства по умолчанию.
Типы Mapped на кортежах и массивах
В TypeScript 3.1 типы объектов mapped теперь работают так же, как при итерации по кортежам и массивам. Это означает, что при использовании существующих типов mapped, таких как Partial
или Required
из lib.d.ts
, они автоматически работают с кортежами и массивами. Благодаря этому TypeScript лучше выражает функции, подобные Promise.all
.
type MapToPromise<T> = { [K in keyof T]: Promise<T[K]> };
type Coordinate = [number, number]
type PromiseCoordinate = MapToPromise<Coordinate>; // [Promise<number>, Promise<number>]
MapToPromise
принимает тип T
, и если этот тип является кортежем как Coordinate
, то преобразуются только числовые свойства. В [number, number]
есть два пронумерованных свойства: 0
и 1
. При предоставлении подобного кортежа MapToPromise
создает новый кортеж, в котором свойства 0
и 1
являются Promise
оригинального типа. Таким образом, результирующий тип PromiseCoordinate
приобретает тип [Promise<number>, Promise<number>]
.
Выбор версий
Это функция, появившаяся в версии TypeScript 3.1, с помощью которой как разработчик, так и компилятор, могут использовать новые функции и одновременно отслеживать используемые версии. При использовании разрешения модуля Node в TypeScript 3.1, когда TypeScript открывает файл package.json
, чтобы выяснить, какие файлы нужно прочитать, он сначала просматривает новое поле typesVersions
. package.json
с полем typesVersions
выглядит следующим образом:
{
"name": "package-name",
"version": "1.0",
"types": "./index.d.ts",
"typesVersions": {
">=3.1": { "*": ["ts3.1/*"] }
}
}
Этот package.json
говорит TypeScript о том, что нужно проверить, работает ли текущая версия TypeScript. Если это 3.1 или более поздняя версия, он определяет путь, импортированный относительно пакета, и считывает из папки пакета ts3.1
.
strictBindCallApply
В JavaScript есть методы bind
, call
и apply
, которые используются в функциях. С их помощью можно выполнять такие действия, как привязка this
и частичное применение аргументов, вызов функции с различным значением для this
и вызов функции с массивом для аргументов. Команде TypeScript потребовалось некоторое время, чтобы смоделировать эти функции, и все они первоначально использовали любое количество аргументов и возвращали любые значения.
В TypeScript 3.1 типы параметров объединены с концепцией списков параметров моделирования с типами tuple, чтобы обеспечить более строгую проверку bind
, call
и apply
при использовании нового флага strictBindCallApply
. При использовании этого флага методы в вызываемых объектах описываются новым глобальным типом CallableFunction
, который объявляет более строгие версии сигнатур для bind
, call
и apply
.
Это выглядит следующим образом:
function foo(a: number, b: string): string {
return a + b;
}
let a = foo.apply(undefined, [10]); // ошибка: слишком мало аргументов
let b = foo.apply(undefined, [10, 20]); // ошибка: второй аргумент - это число
let c = foo.apply(undefined, [10, "hello", 30]); // ошибка: слишком много аргументов
let d = foo.apply(undefined, [10, "hello"]); // все в порядке! возвращает строку
Таким образом, независимо от того, выполняется ли сложное метапрограммирование или используются простые шаблоны, такие как методы привязки в экземплярах классов, эта функция помогает обнаружить множество ошибок.
Поддержка BigInt
BigInt
— это встроенный объект для представления целых чисел от 2 до 53, которое является наибольшим числом, представленное JavaScript с помощью примитива Number
. В TypeScript 3.2 предусмотрена проверка типов для BigInts, а также поддержка выделения литералов BigInt при отслеживании esnext
.
Синтаксис в TypeScript для нового примитивного типа называется bigint
. bigint
можно получить с помощью вызова функции BigInt()
или литерала BigInt, добавив n
в конец любого целочисленного литерала:
let foo: bigint = BigInt(100); // функция BigInt
let bar: bigint = 100n; // литерал BigInt
// Здесь возвращаются целые числа, которые могут стать очень большими!
function fibonacci(n: bigint) {
let result = 1n;
for (let last = 0n, i = 0n; i < n; i++) {
const current = result;
result += last;
last = current;
}
return result;
}
fibonacci(10000n)
Наследование tsconfig.json через пакеты Node.js
В TypeScript 3.2 tsconfig.json
теперь может работать из node_modules
. При использовании пустого пути для поля "extends"
в tsconfig.json
, TypeScript самостоятельно откроет пакеты node_modules
.
{
"extends": "@my-team/tsconfig-base",
"include": ["./**/*"]
"compilerOptions": {
// Переопределение некоторых параметров для каждого проекта.
"strictBindCallApply": false,
}
}
Здесь TypeScript поднимается по папкам node_modules
в поисках пакета @my-team/tsconfig-base
. В каждом из этих пакетов TypeScript сначала проверяет, содержит ли package.json
поле "tsconfig"
, а затем пытается загрузить файл конфигурации из этого поля. Если его не существует, то TypeScript попытается прочитать из tsconfig.json
в root. Это схоже с процессом поиска файлов .js
в пакетах, которые использует Node, и процессом поиска .d.ts
, уже используемым TypeScript. Представьте, насколько это удобно для больших проектов.
const assertions
TypeScript 3.4 представляет новую конструкцию для литеральных значений, которая называется const
утверждениями. Синтаксис является типом утверждения с const
вместо названия типа (например, 123 as const
). При создании новых литеральных выражений с const
утверждениями можно сообщить языку, что массивы являются кортежами только для чтения или что литералы объектов получают свойства только для чтения.
// Type '"hello"'
let x = "hello" as const;
// Type 'readonly [10, 20]'
let y = [10, 20] as const;
// Type '{ readonly text: "hello" }'
let z = { text: "hello" } as const;
Проверка типов globalThis
Команда TypeScript также исправила проблемы получения доступа к значениям в глобальной области видимости. В новом TypeScript 3.4 появилась поддержка проверки типов для новой глобальной переменной globalThis в ECMAScript, которая указывает на глобальную область видимости. В отличие от других решений, globalThis предоставляет стандартный способ для получения доступа к глобальной области действия, который можно использовать в различных окружениях.
// в глобальном файле:
var abc = 100;
// Ссылается на 'abc' выше.
globalThis.abc = 200;
Примечание: глобальные переменные, объявленные с let
и const
, не обнаруживаются с globalThis
.
Перевод статьи Nwose Lotanna: New Features in TypeScript You Didn’t Know Exist