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

Перемещаемые типы

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

Это потому, что TypeScript разработан, чтобы позволить вам беспрепятственно работать с высокодинамичным языком, таким как JavaScript. Здесь мы рассмотрим несколько приемов перемещения типов в TypeScript.

Ключевая причина использовать их: вы меняете одну вещь, а все остальное обновляется автоматически, и вы получаете полезные ошибки, если что-то ломается, как в хорошо разработанной системе ограничений.

Копирование как типа, так и значения

Если вы хотите переместить класс, у вас может возникнуть соблазн сделать следующее:

class Foo {}
var Bar = Foo;
var bar: Bar; // ОШИБКА: не могу найти имя 'Bar'

Это ошибка, потому что var скопировал Foo только в область объявления переменной, и поэтому вы не можете использовать Bar в качестве описания типа. Правильный способ - использовать ключевое слово import. Обратите внимание, что вы можете использовать ключевое слово import таким образом, только если вы используете пространства имен или модули (подробнее об этом позже):

namespace importing {
    export class Foo {}
}

import Bar = importing.Foo;
var bar: Bar; // Okay

Этот трюк с import работает только для того что имеет и тип и переменную.

Захват типа переменной

На самом деле вы можете использовать переменную в описании типа, используя оператор typeof. Это позволяет вам сообщить компилятору, что одна переменная имеет тот же тип, что и другая. Вот пример, демонстрирующий это:

var foo = 123;
var bar: typeof foo; // `bar` имеет тот же тип, что и `foo` (здесь `number`)
bar = 456; // Okay
bar = '789'; // ОШИБКА: Тип `string` не может быть назначен типу `number`

Захват типа члена класса

Вы можете погрузиться в объект любого типа (кроме null), чтобы получить тип свойства:

class Foo {
    foo: number; // член класса, тип которого мы хотим захватить
}

let bar: Foo['foo']; // `bar` имеет тип `number`

В качестве альтернативы, как и при захвате типа переменной, вы можете просто объявить переменную только для целей захвата типа:

// Только для захвата типа
declare let _foo: Foo;

// То же, что и раньше
let bar: typeof _foo.foo; // `bar` имеет тип  `number`

Захват типа магических строк

Многие JavaScript библиотеки и фреймворки работают с необработанными строками JavaScript. Вы можете использовать переменные const для захвата их типа, например:

// Захватываем и *тип* и *значение* магической строки:
const foo = 'Hello World';

// Используем захваченный тип:
let bar: typeof foo;

// на bar может быть назначено только `Hello World`
bar = 'Hello World'; // Okay!
bar = 'anything else '; // Ошибка!

В этом примере bar имеет литеральный тип Hello World. Мы рассматриваем это подробнее в разделе литеральных типов.

Захват типа по имени ключей

Оператор keyof позволяет вам захватывать тип по имени ключей. Например. вы можете использовать его для захвата типов имен ключей переменной, сначала получая её тип с помощью typeof:

const colors = {
    red: 'reddish',
    blue: 'bluish',
};
type Colors = keyof typeof colors;

let color: Colors; // тоже самое что и let color: "red" | "blue"
color = 'red'; // okay
color = 'blue'; // okay
color = 'anythingElse'; // Ошибка: Тип '"anythingElse"' не возможно присвоить
// типу '"red" | "blue"'

Это позволяет вам легко создавать такие вещи, как строковые перечисления + константы, как вы только что видели в приведенном выше примере.