玩转Typescript(六):TypeScript高级类型(下)

325 阅读2分钟

这是我参与11月更文挑战的第 6 天,活动详情查看:2021最后一次更文挑战

字符串字面量类型

字符串字面量类型允许你指定字符串必须的固定值。

type Easing = "ease-in" | "ease-out" | "ease-in-out";
class UIElement {
  animate(dx: number, dy: number, easing: Easing) {
    if (easing === "ease-in") {
    }
    else if (easing === "ease-out") {
    }
    else if (easing === "ease-in-out") {
    }
  }
}
let button = new UIElement();
button.animate(0, 0, "ease-in");
// button.animate(0, 0, "uneasy"); // error: Argument of type '"uneasy"' is not assignable to parameter of type 'Easing'.

数字字面量类型

function rollDie(): 1 | 2 | 3 | 4 | 5 | 6 {
  // ...
}

枚举成员类型

当每个枚举成员都是用字面量初始化的时候枚举成员是具有类型的。

enum ShapeKind {
  Circle,
  Square,
}
interface Circle {
  kind: ShapeKind.Circle;
  radius: number;
}
interface Square {
  kind: ShapeKind.Square;
  sideLength: number;
}
let c: Circle = {
  kind: ShapeKind.Square,
  // Error! Type 'ShapeKind.Square' is not assignable to type 'ShapeKind.Circle'.
  radius: 100,
}

可辨识联合(Discriminated Unions)

首先我们声明了将要联合的接口。 每个接口都有 kind属性但有不同的字符串字面量类型。 kind属性称做 可辨识的特征标签

// 声明将要联合的接口
interface Square {
  kind: "square";
  size: number;
}
interface Rectangle {
  kind: "rectangle";
  width: number;
  height: number;
}
interface Circle {
  kind: "circle";
  radius: number;
}
type Shape = Square | Rectangle | Circle; // 类型别名
function area(s: Shape) {
  switch (s.kind) { // kind属性上的类型保护
    case "square": return s.size * s.size;
    case "rectangle": return s.height * s.width;
    case "circle": return Math.PI * s.radius ** 2;
  }
}

索引类型(Index types)

一个常见的JavaScript模式是从对象中选取属性的子集。

function pluck(o, names) {
  return names.map(n => o[n]);
}

在TypeScript中,写法如下:

function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
  return names.map(n => o[n]);
}
interface Person {
  name: string;
  age: number;
}
let person: Person = {
  name: 'Jarid',
  age: 35
};
let strings: string[] = pluck(person, ['name']); // ok, string[]

编译器会检查 name是否真的是 Person的一个属性。

首先,对于任何类型 T, keyof T的结果为 T 上已知的公共属性名的联合。例如:

let personProps: keyof Person; // 'name' | 'age'

其次,T[K]索引访问操作符,person['name'] 具有类型 Person['name']。

索引类型和字符串索引签名

  • 如果你有一个带有字符串索引签名的类型,那么 keyof T会是 string | number

  • T[string]为索引签名的类型:

interface Fn<T> {
  [key: string]: T;
}
let keys: keyof Fn<number>; // string | number
let value: Fn<number>['foo']; // number

映射类型

TypeScript提供了从旧类型中创建新类型的一种方式 — 映射类型。在映射类型里,新类型以相同的形式去转换旧类型里每个属性。例如,你可以令每个属性成为 readonly类型或可选的。

映射类型也就是之前讲到的工具类型,如Partial<T>Readonly<T>等。

参考