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

Литералы

Литералы - это фиксированные значения, которые являются примитивами JavaScript.

Строковые литералы

Вы можете использовать строковый литерал в качестве типа. Например:

1
let foo: 'Hello';

Здесь мы создали переменную с именем foo, которая позволяет присваивать ей только литеральное значение 'Hello'. Это продемонстрировано ниже:

1
2
let foo: 'Hello';
foo = 'Bar'; // Ошибка: "Bar" нельзя назначить типу "Hello"

Они не очень полезны сами по себе, но могут быть собраны в тип объединение для создания мощной (и полезной) абстракции, например:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
type CardinalDirection =
    | 'North'
    | 'East'
    | 'South'
    | 'West';

function move(
    distance: number,
    direction: CardinalDirection
) {
    // ...
}

move(1, 'North'); // Okay
move(1, 'Nurth'); // Ошибка!

Другие литеральные типы

TypeScript также поддерживает литеральные типы boolean и number, например:

1
2
type OneToFive = 1 | 2 | 3 | 4 | 5;
type Bools = true | false;

Логический вывод

Как правило, вы получаете сообщение об ошибке: Тип string не может быть назначен для типа "foo". Следующий пример демонстрирует это.

1
2
3
4
5
6
function iTakeFoo(foo: 'foo') {}
const test = {
    someProp: 'foo',
};
iTakeFoo(test.someProp); // Ошибка: Аргумент типа string не может быть
// назначен параметру типа 'foo'

Это потому, что test подразумевает тип {someProp: string}. Решением в этом случае было бы использование простого утверждения типа. Для того чтобы сообщить TypeScript литерал, который вы хотите, чтобы он выводил, как показано ниже:

1
2
3
4
5
function iTakeFoo(foo: 'foo') { }
const test = {
  someProp: 'foo' as 'foo'
};
iTakeFoo(test.someProp); // Okay!

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

1
2
3
4
5
6
7
8
9
function iTakeFoo(foo: 'foo') {}
type Test = {
    someProp: 'foo',
};
const test: Test = {
    // Пометки - подразумевается, что someProp всегда === 'foo'
    someProp: 'foo',
};
iTakeFoo(test.someProp); // Okay!

Случаи использования

Возможные варианты использования для строковых литералов:

Тип перечисление на основе строк

Тип перечисление в TypeScript основан на числах. Вы можете использовать строковые литералы вместе с объединенными типами, чтобы сымитировать перечисление на основе строки, как мы это делали в примере CardinalDirection выше. Вы даже можете сгенерировать структуру Key: Value, используя следующую функцию:

1
2
3
4
5
6
7
8
9
/** Утилита для создания K:V из списка строк */
function strEnum<T extends string>(
    o: Array<T>
): { [K in T]: K } {
    return o.reduce((res, key) => {
        res[key] = key;
        return res;
    }, Object.create(null));
}

А затем сгенерируйте тип объединение из литеральных типов, используя keyof typeof. Вот полный пример:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/** Утилита для создания K:V из списка строк */
function strEnum<T extends string>(
    o: Array<T>
): { [K in T]: K } {
    return o.reduce((res, key) => {
        res[key] = key;
        return res;
    }, Object.create(null));
}

/**
 * Пример создания типа объединение на основе строк
 */

/** Создать K:V */
const Direction = strEnum([
    'North',
    'South',
    'East',
    'West',
]);
/** Создать тип */
type Direction = keyof typeof Direction;

/**
 * Пример использования типа объединение на основе строк
 */
let sample: Direction;

sample = Direction.North; // Okay
sample = 'North'; // Okay
sample = 'AnythingElse'; // ОШИБКА!

Моделирование имеющихся JavaScript API

Например В редакторе CodeMirror есть опция readOnly, которая может быть либо boolean, либо литеральной строкой "nocursor" (валидные допустимые значения true,false,"nocursor"). Это может быть объявлено как:

1
readOnly: boolean | 'nocursor';

Размеченные объединения

Мы расскажем об этом позже в книге.

Комментарии