实际代码过程中使用 TS 必然需要创建一些新的类型。 本文简要介绍了一些创建自己类型所需要的方法
泛型 采用参数的类型
keyof 运算符
keyof 运算法主要获取对象类型的 key
- 输入是一个类型
- 输出是这个类型所有的 key 构成的一个联合类型
typeof 类型运算符
typeof 就是获取这个变量的类型
- 输入是☝一个变量
- 输出是他对应的类型
type索引访问类型
索引访问类型就是将JS 当中对象的语法交给类型
- 输入是一个类型+方括号语法
- 方括号里面的内容必须是一个类型
- 输出是类型会是对应索引指向的类型
方括号里面可以是一个属性的名称,也可以是一个联合类型。
值得注意的是我们可以对一个数组使用索引访问。下面联合用了 typeof 和索引访问的方法。注意他的执行顺序
const MyArray = [
{ name: "Alice", age: 15 },
{ name: "Bob", age: 23 },
{ name: "Eve", age: 38 },
];
type Person = (typeof MyArray)[number];
type Person = typeof MyArray[number];
条件类型
条件类型可以分为两类。
- 一个是简单的判断,告诉编译器一些限制。
- 一个则类似三目运算符,来构造新的对象
type Flatten<T> = T extends any[] ? T[number] : T;
除了用索引访问类型,我们还可以用 infer 关键字。
- infer 关键字主要用在 extends 后面的表达式中
type Flatten<Type> = Type extends Array<infer Item> ? Item : Type;
type GetRType<Type> = Type extends (...args: never[]) => infer Return? Return: never;
如果条件类型输入是个联合类型,则条件类型将应用于该联合的每个成员后再联合起来。
映射类型
说映射类型之前要先明确什么是索引签名。
- 索引签名是一种定义事先未知的字段的 Shape 的方法。类似下面的代码
interface StringByString {
[key: string]: string;
}
- 索引签名只接受 string、number 或 symbol 作为键类型,如果想用字符串联合类型等其他类型可以用 Record
映射类型是一种泛型类型,他需要把另一种类型映射到一种新类型。
type CreateMutable<Type> = {
-readonly [Property in keyof Type]: Type[Property];
};
- readonly 和 ?分别影响可变性和可选性
- 通过在 - 或 + 前加上前缀来删除或添加这些修饰符
映射类型可以如何修改属性名称? 假设我们知道一个对象,现在希望用 get 和 set 来修饰他的属性名。
type Getters<Type> = {
[Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
};
模板文本类型
模版文本可以帮助我们根据 union literal类型生成多个literal类型 如下列代码会生成 2*3种类型
type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff"|"nolocal";
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
需要注意这里代表的是一种类型,而不是变量。
这个很重要。如在理解下面的${string & keyof Type}Changed时,如果以为只是一个变量,那么就会一头雾水。实际这里是找到Type 类型所有 string 的属性,给 on 方法第一个函数添加一个xxxChanged的字符串限制。
type PropEventSource<Type> = {
on(eventName: `${string & keyof Type}Changed`, callback: (newValue: any) => void): void;
};
union类型
可以看到同样是泛式类型,在输入的时候判断和具体运算的时候判断是不同的
- 具体运算判断输出的还是一个union类型
- 输入的时候判断则会合成一体。
type ToArray<Type> = Type extends any ? Type[] : never;
type StrArrOrNumArr = ToArray<string | number>;
type EventConfig<Events extends { kind: string }> = {
[E in Events as E["kind"]]: (event: E) => void;
}
type SquareEvent = { kind: "square", x: number, y: number };
type CircleEvent = { kind: "circle", radius: number };
type Config = EventConfig<SquareEvent | CircleEvent>