TS中高级类型工具及其源码解析(含示例)
一、前言
最近入职了新公司也有两个月左右了,公司主要技术栈是 React 和 TS,然而我平时用的TS并不多,刚好借此机会最近也是好好的学习了一番TS的高级工具类型及其源码
本文主要介绍的是TS的高级类型工具,含有TS高级类型工具的源码解释,及其示例,需要对TS有一定了解,或者已经实际用过一段时间
二、前置知识
1、关键字 extends
准确的来说这是一个条件类型
,它借用了 javascript 的条件运算符,语法如下
T extends U ? X :Y
解释:
- 在该语法示例中, extends 是关键字; T、 U、 X 和 Y 均表示一种类型。
- 若类型 T 能
赋值
给类型 U,则条件类型的结果就是类型 X,反之结果为类型 Y - 当然这个关键字如果用到 interface 上就是继承的作用了,这儿就不做过多的解释
2、关键字 in
这是一个遍历语法的关键字, 语法如下
type K = "a" | "b"
type B = { [P in K]: number } // { a: number; b: number}
解释:
- 在结果对象类型中创建一个新的属性成员, 属性名为P, 属性值为 number
- P 是类型变量,代表每次遍历出来的成员类型,并且 P 可以作为对象属性值的类型 类似这样:
[P in K]: P
- K 表示要遍历的类型, 由于遍历的结果类型要作为对象属性名, 因此类型 K 必须能够赋值给联合类型
string | number | symbol
3、关键字 readonly
这个比较简单,就代表了这个类型是否为只读类型
interface A {
readonly a: string;
b: number;
}
const test: A = {
a: "",
b: 0
}
test.b = 1;
// test.a = "1" // a 为 readonly 不可更改
4、关键字 keyof
用来获取一个类型的键值,并返回一个联合类型
interface A {
a: number;
b: string;
}
type B = keyof A; // "a" | "b"
5、关键字 typeof
这是一个类型查询的关键字,可以获取操作数的类型
const A = {
a: 1,
b: "2"
}
type B = typeof A; // { a: number; b: string }
5、关键字 infer
这个关键字主要用来定义一个可推断的类型, 用的比较多的地方就是用来获取函数的参数类型
type CT<T> = T extends Array<infer U> ? U : never;
type T = CT<Array<number>> // number
type CT1<T> = T extends (arg: infer U) => void ? U : T;
type T1 = CT1<(a: boolean) => void> // boolean
6、修饰符的加减
TS中引入了两个修饰符来精确控制添加或者移除映射属性的 "?" 修饰符
和 readonly 修饰符
type T0<T> = { -readonly [P in keyof T]-?: T[P] };
type T1<T> = { +readonly [P in keyof T]+?: T[P] };
解释:
- "+" 修饰符,为映射属性添加 "?" 修饰符或者 readonly
- "-" 修饰符,为映射属性移除 "?" 修饰符或者 readonly
- "+" 或者 "-" 修饰符必须应用在 "?" 修饰符或者 readonly 之前
- 对于 "+" 修饰符, 明确的添加与省略它的作用是相同的,所以通常都省略。 例如
"+readonly" 等同于 "readonly"
三、高级类型工具
1. Partial<T>
源码:
type Partial<T> = {
[P in keyof T]?: T[P];
};
该工具类型可以构造一个新的类型,并把实际类型参数 T 中的属性
全变成可选属性
interface A {
x: number;
y: number;
}
type T = Partial<A>; // {x?number; y?:number}}
2. Required<T>
源码:
type Required<T> = {
[P in keyof T]-?: T[P];
};
和 Partial 相反, 把T 中的属性
全变成必选属性
interface A {
x?: number;
y: number;
}
type T = Required<A>; // {x:number; y:number}}
3. Readonly<T>
源码:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
该工具类型可以构造一个新的类型, 并将类型参数 T 中的所有属性变成
只读属性
interface A {
x: number;
y: number;
}
type T = Readonly<A>; // {x:number; y:number}}
const a: T = { x: 0, y: 0 }
// a.x = 1 无法分配到 "x" ,因为它是只读属性
// a.y = 1 无法分配到 "y" ,因为它是只读属性
4. Record<K, T>
源码:
type Record<K extends keyof any, T> = {
[P in K]: T;
};
该工具类型可以使用给定的 对象属性名类型 和 对象属性类型,
创建一个新的对象类型
type K = 'x' | 'y';
type T = number;
type R = Record<K, T>; // {x:number; y:number}}
const a: R = { x: 0, y: 0 }
5. Exclude<T, U>
源码:
type Exclude<T, U> = T extends U ? never : T;
该工具类型可以从类型 T 中
剔除
所有可以赋值给类型 U 的类型
type T0 = Exclude<"a" | "b", 'x'>; // "a" | "b"
type T1 = Exclude<string | (() => void), Function>; // string
6. Extract<T, U>
源码:
type Extract<T, U> = T extends U ? T : never;
该工具类型和 Exclude<T, U>类型互补, 它能从类型 T 中
获取
所有可以赋值给类型 U 的类型
type T0 = Extract<"a" | "b", 'a'>; // "a"
type T1 = Extract<string | (() => void), Function>; // () => void
type T2 = Extract<"a" | "b", 'c'>; // never
7. Pick<T, K>
源码:
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
该工具能出已有对象类型中
选取给定的属性以及其类型
,然后构建一个新的对象类型
interface A {
x: number;
y: number;
}
type T0 = Pick<A, 'x'>; // {x:number}
type T1 = Pick<A, 'x' | 'y'>; // {x:number; y:number}
// type T3 = Pick<A, 'z'> 类型“"z"”不满足约束“keyof A”
8. Omit<T, K>
源码:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
该工具与 Pick<T, K> 类型互补,能从已有对象类型中
剔除给定的属性
,然后构建一个新的对象类型
interface A {
x: number;
y: number;
}
type T0 = Omit<A, 'x'>; // {y:number}
type T1 = Omit<A, 'x' | 'y'>; // {}
type T3 = Omit<A, 'z'>; // {}
9. NonNullable<T>
源码:
type NonNullable<T> = T extends null | undefined ? never : T;
该工具类型能从类型 T 中
剔除 null 和 undefined 类型
,并构建一个新的类型
type T0 = NonNullable<string | number | null | undefined>; // string | number
10. Parameters<T>
源码:
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
该工具类型能
获取函数类型 T 的参数类型
,并使用参数类型构建一个元组类型
type T0 = Parameters<() => void>; // []
type T1 = Parameters<(a: string) => void>; // [string]
type T2 = Parameters<(a: string, b: number) => void>; // [string, number]
type T3 = Parameters<(x: { a: number, b: string }) => void>; // [{ a: number; b: string }]
11. ConstructorParameters<T>
源码:
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
该工具类型能获取
构造函数 T 中的参数类型
, 并使用参数类型构造一个元组类型。 若 T 不是函数类型,则`返回 never 类型
type T0 = ConstructorParameters<new (s?: string) => object>; // [s?: string | undefined]
12. ReturnType<T>
源码:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
该工具类型能获取
函数类型 T 的返回值类型
type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<() => { a: string, b: number }>; // { a: string; b: number }
13. InstanceType<T>
源码:
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
该工具类型能获取
构造函数的返回值类型
class A {
x = 0;
}
type T0 = InstanceType<typeof A>; // A
type T1 = InstanceType<new (s?: string) => object>; // object
14. ThisParameterType<T>
源码:
type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown;
该工具类型能
获取函数类型 T 中的 this 参数类型
,若函数类型定义中没有 this 参数,则返回 unknown 类型
function fn(this: object, x: number) { }
function fn1(x: number) { }
type T0 = ThisParameterType<typeof fn> // object
type T1 = ThisParameterType<typeof fn1> // unknown
15. OmitThisParameter<T>
源码:
type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;
该工具类型能从类型 T 中
剔除 this 参数类型
,并构造一个新类型
function fn(this: object, x: number) { }
type T0 = OmitThisParameter<typeof fn> // (x: number) => void
四、结语
本文中,对常见的关键字和常用的高级类型工具进行了讲解, 主要平时开发的时候还是要多用、多积累。
最后,文中如有错误,欢迎大家在评论区指正,如果本文对你有帮助, 记得点赞👍
和关注❤️
如需转载请标明作者和出处
转载自:https://juejin.cn/post/7100737388128763918