字面量类型

字面量是 JavaScript 本身提供的一个准确变量。

字符串字面量

你可以使用一个字符串字面量做为一个类型:

  1. let foo: 'Hello';

在这里,我们创建了一个被称为 foo 变量,它仅接收一个字面量值为 Hello 的变量:

  1. let foo: 'Hello';
  2. foo = 'Bar'; // Error: 'bar' 不能赋值给类型 'Hello'

它们本身并不是很实用,但是可以在一个联合类型中组合创建一个强大的(实用的)抽象:

  1. type CardinalDirection = 'North' | 'East' | 'South' | 'West';
  2. function move(distance: number, direction: CardinalDirection) {
  3. // ...
  4. }
  5. move(1, 'North'); // ok
  6. move(1, 'Nurth'); // Error

其他字面量类型

TypeScript 同样也提供 booleannumber 的字面量类型:

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

推断

通常,你会得到一个类似于 Type string is not assignable to type 'foo' 的错误,如下:

  1. function iTakeFoo(foo: 'foo') {}
  2. const test = {
  3. someProp: 'foo'
  4. };
  5. iTakeFoo(test.someProp); // Error: Argument of type string is not assignable to parameter of type 'foo'

这是由于 test 被推断为 { someProp: string },我们可以采用一个简单的类型断言来告诉 TypeScript 你想推断的字面量:

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

或者使用类型注解的方式,来帮助 TypeScript 推断正确的类型:

  1. function iTakeFoo(foo: 'foo') {}
  2. type Test = {
  3. someProp: 'foo';
  4. };
  5. const test: Test = {
  6. // 推断 `someProp` 永远是 'foo'
  7. someProp: 'foo'
  8. };
  9. iTakeFoo(test.someProp); // ok

使用用例

TypeScript 枚举类型是基于数字的,你可以使用带字符串字面量的联合类型,来模拟一个基于字符串的枚举类型,就好像上文中提出的 CardinalDirection。你甚至可以使用下面的函数来生成 key: value 的结构:

  1. // 用于创建字符串列表映射至 `K: V` 的函数
  2. function strEnum<T extends string>(o: Array<T>): { [K in T]: K } {
  3. return o.reduce((res, key) => {
  4. res[key] = key;
  5. return res;
  6. }, Object.create(null));
  7. }

然后,你就可以使用 keyoftypeof 来生成字符串的联合类型。下面是一个完全的例子:

  1. // 用于创建字符串列表映射至 `K: V` 的函数
  2. function strEnum<T extends string>(o: Array<T>): { [K in T]: K } {
  3. return o.reduce((res, key) => {
  4. res[key] = key;
  5. return res;
  6. }, Object.create(null));
  7. }
  8. // 创建 K: V
  9. const Direction = strEnum(['North', 'South', 'East', 'West']);
  10. // 创建一个类型
  11. type Direction = keyof typeof Direction;
  12. // 简单的使用
  13. let sample: Direction;
  14. sample = Direction.North; // Okay
  15. sample = 'North'; // Okay
  16. sample = 'AnythingElse'; // ERROR!

辨析联合类型

我们将会在此书的稍后章节讲解它。

原文: https://jkchao.github.io/typescript-book-chinese/typings/literals.html