TypeScript 第四章 高级类型
1. 高级类型
1. 重载签名
- 重载签名允许你在同一个函数名称下定义多个不同的函数签名,每个签名有不同的参数列表和返回类型。实际的函数实现只需要一个,并且必须匹配其中一个签名。
在 TypeScript 中,函数签名定义了函数的参数列表和返回类型。一个函数签名包括:
- 参数列表(参数名和类型)
- 返回类型
function sum(arg1: number, arg2: number):number;
function sum(arg1: string, arg2: string):string;
function sum (arg1,arg2){
return arg1+arg2;
}
// 在 TypeScript 中,当你使用重载签名时,编译器会根据实际传递的参数类型来决定使用哪个重载签名。具体来说,编译器会根据参数的实际类型匹配最合适的重载签名。
console.log(sum(1,2)); // 3
console.log(sum('1','2')) // '12'
- 在 TypeScript 中,当你看到 +1 overload 的提示时,这意味着当前函数定义中存在一个或多个重载签名(overload signatures)。具体来说,这个提示表明除了当前显示的函数签名外,还有至少一个额外的重载签名。
2. 条件类型 T extends U ? X : Y
- 语法:
T extends U ? X : Y
使用了继承关键字extend和三元运算符 - 含义:
T类型
是否继承自U类型
,如果是则T
是X类型
,不是则T
是Y类型
- 简单的示例
type ExtractNumberOrString<T> = T extends number | string ? T : never;
// 测试
type Test1 = ExtractNumberOrString<number>; // 结果为 number
type Test2 = ExtractNumberOrString<string>; // 结果为 string
type Test3 = ExtractNumberOrString<boolean>; // 结果为 never
- 将上面的重载签名的函数改为泛型的条件类型
function sum<T extends number | string>(
arg1: T,
arg2: T
): T extends number ? number : string;
function sum(arg1,arg2){
return arg1 + arg2
}
console.log(sum(1,2)); // 3
console.log(sum('1','2')) // '12'
3. 类型推断 infer
infer
要和条件类型T extends U ? X : Y
一起使用- 自己的理解:
infer
的作用确实是做类型推断,在实际使用中可以理解为声明了一个类型参数,比如下面的例子中就理解为在返回值的地方声明了一个类型参数R,等实参传过来的时候,R就是实参的类型
- 示例:计算函数的返回值类型
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;
- 分析:
<T extends (...args: any[]) => any>
:T类型被约束为一个函数类型T extends (...args: any[]) => any ? X : Y
:这种结构是条件类型,如果T类型是函数类型,则返回X类型,不是则返回Y类型;因为T类型已经在传入时就确定为函数类型,所以此处必定为真T extends (...args: any[]) => infer R
:infer R
代替了上面的any
,infer R
推断此处的类型为RT extends (...args: any[]) => infer R ? R : any
连起来就是,首先T肯定是个函数类型,infer R
:返回值类型推断为R,下面做条件判断,T如果是函数类型,则返回推导出的R类型,不是则无所谓因为T肯定是函数类型。
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;
function foo(){
return 1
}
type Foo = ReturnType<typeof foo>
4. 分发条件类型
|
:虽然|
不是泛型中的关键字,分发类型中必须有它- 也必须与
T extends U ? X : Y
相结合
type toArray<T> = T[]
type newType = toArray<number|string> //newType = (string|number)[]
type toArray1<T> = T extends any ? T[] : never
// 联合类型遇到条件类型就变成了分发类型,会将联合类型中每一项单独运算然后再联合
type newType1 = toArray1<number|string> // newType1 = string[] | number[]
// 区别
// [1,2,3] 是 newType类型也是newType1类型
// ['1',2,3] 是newType类型,但不是newType1类型
2. TypeScript内置的类型工具
1. Partial<T>:把类型T内所有属性变为可选
interface Person {
name: string;
age: number;
}
type newType = Partial<Person>
// newType相当于
type newType = {
name?: string;
age?: number;
}
- 实现过程
interface Person {
name: string;
age: number;
}
type ToPartial<T> = {
[P in keyof T]?: T[P];
};
type MyPartial = ToPartial<Person>;
- 分析
- 传入一个对象类型T
keyof T
:baT类型中key组成一个联合类型,例子中就组成:name | age
[P in keyof T]?
关键字in
就是遍历,P遍历key的联合类型;这里相当于把T的key都遍历一次,并且在后面加上?
可选属性T[P]
:T是整个对象,P是key,那T[P]
就是value
2. Required<T> :把类型T所有属性变为必选
- 示例
interface Person {
name?: string;
age?: number;
}
type RequiredPerson = Required<Person>;
// RequiredPerson 等价于
// {
// name: string;
// age: number;
// }
- 实现过程
type myRequired<T> = {
[P in keyof T]-?: T[P];
}
- 解析
- 过程类似于Partial
- 不同之处
-?
,去掉属性的可选
3. ReadOnly<T> :把类型T 内所有属性变为只读
interface Person {
name: string;
age: number;
}
type ReadonlyPerson = Readonly<Person>;
// ReadonlyPerson 等价于
// {
// readonly name: string;
// readonly age: number;
// }
- 实现过程
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
- 解析
- 过程类似于Partial
- 不同之处
readonly
,所有属性加上readonly
4. Record 把两种类型组合成一个新类型
Record<K extends keyof any, T>
type RecordType = Record<Keys, Value>
// 其中keys满足联合类型的约束条件
// keys = "name" | "age" | "adress"
- 示例1:合并两种类型
type keys = "上海" | "北京";
type value = {
人口: number;
面积: number;
};
type newType = Record<keys, value>;
const obj: newType = {
上海: {
人口: 100,
面积: 200,
},
北京: {
人口: 200,
面积: 300,
},
};
- 示例2:将属性的类型一起改变
type value = {
人口: number;
面积: number;
};
type newType2 = NewRecord<keyof value, string>;
// type newType2 = {
// 人口: string;
// 面积: string;
// }
- 实现过程
type NewRecord<T extends keyof any, R> = {
[key in T]: R;
};
- 解析
keyof any
:keyof
的作用是取对象的属性,返回的是联合类型,keyof any
这里的作用主要是想说明这里是联合类型T extends keyof any
:T被约束为联合类型[key in T]
:in关键字的后面只能是联社类型,这里就是在遍历联合类型T
5. Pick 挑选对象内的部分属性
Pick<T, K extends keyof T>
interface Info {
name: string;
age: number;
address: string;
}
// 选择了对象中 name和 age属性
type newInfo = Pick<Info, "name" | "age">
// type newInfo = {
// name: string;
// age: number;
// }
- 自己实现pick
interface Info {
name: string;
age: number;
address: string;
}
type newPick<T, V extends keyof T> = {
[k in V]: T[k];
};
type newInfo2 = newPick<Info, "name" | "age">;
- 解析:
V extends keyof T
:V被约束为T类型中key的联合类型也就是:‘name’|‘age’|‘address’[k in V]
:遍历所有的V,形成新的keyT[k]
:T类型中K属性对应的值
6. Omit 把对象内部分属性删除
- 官方实现:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
interface Info {
name: string;
age: number;
gender: string;
}
type newInfo = Omit<Info, "name" | "age">;
// type newInfo = {
// gender: string;
// }
- 自己实现omit
type newOmit<T, K extends keyof T> = {
[P in keyof T as P extends K ? never : P]: T[P];
};
type newInfo1 = newOmit<Info, "name" | "age">;
- 解析:
P in keyof T
:P遍历整个T的keyP in keyof T as P
:遍历后命名为P,且只能命名为P,我觉得最后这个P就是前面P in keyof T
遍历时的返回值,像是filfter里面的item
P extends K ? never : P
:P是否在K的组合类型中,在则弃用,不在则返回[P in keyof T as P extends K ? never : P]
:整个给我的感觉就像是使用filfter来求差集,遍历一个集合,另一个集合中是否也有这个元素,有则排除,没有则留下,最后返回了两个集合的差集
7. Exclude 排除联合类型中的类型
type Exclude<T, U>
:排除在T类型中的U类型T
必须是联合类型,不然达不到想要的结果
type Info = string | number | boolean
type newInfo = Exclude<Info, string>
// type newInfo = number | boolean
- 自己实现
type Info = string | number | symbol ;
type newExclude<T, U> = T extends U ? never : T;
type newInfo2 = newExclude<Info, string>;
8. Extract 提取两个联合类型中共有的类型,求交集
type Extract<T, U>
:在源码中并没有对T和U做类型约束,但是如果T和U不是联合类型,这么做就没有必要
type Info = string | number | boolean
type Info1 = string | symbol
type newInfo = Extract<Info, Info1>
// type newInfo = string
- 自己实现
type newExtract<T, U> = T extends U ? T : never
// 觉得还可以使用
type newExtract1<T,U> = T & U
9. NonNullable 排除联合类型中的null和undefined
type NonNullable<T>
type Info = string | number | boolean | null | undefined;
type newInfo = NonNullable<Info>;d
// type newInfo = string | number | boolean
- 自己实现
type myNonNullable<T> = T extends null | undefined ? never : T;
- 源码实现方法比较特殊
type NonNullable<T> = T & {};// 交叉类型:既满足T
- 解释:
string & {} 的结果是 string。
number & {} 的结果是 number。
boolean & {} 的结果是 boolean。
null & {} 的结果是 never(因为 null 和 {} 没有公共部分)。
undefined & {} 的结果也是 never(同理)。
10. ReturnType 获取返回值的类型
- ReturnType<T extends (…args: any) => any>
- 参考上面的类型推断infer章节
11. InstanceType 类的实例对象的类型
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
- 解释源码:
new (...args: any) => any
表示构造函数,直接理解为类abstract new (...args: any) => any
:抽象类的构造函数T extends abstract new (...args: any) => any
:传入的类型T既可以是抽象类,也可以是普通的类R
:类的实例类型
- 示例
class Person {}
class Dog {}
// 工厂函数
function factory<T extends new (...arg: any[]) => any>(
ctor: T
): InstanceType<T> {
return new ctor();
}
// 如果没有InstanceType<T>,通过工厂函数实例化的person和dog都是any类型
const person = factory(Person); // person是Person类型
const dog = factory(Dog); // dog是Dog类型
类型中的关键字
- extends:表示类型约束,用于限制泛型参数的范围。T extends R :T类型必须是R类型的子集
- keyof:表示键类型,用于获取对象类型的键。返回的是联合类型:
"类型1" |"类型2"
- extends ?:条件类型。
- infer:用于条件类型中的类型推断。
- never:表示永远不出现的类型,通常用于错误处理或类型排除。
- this:表示当前上下文的对象类型。
- readonly:表示只读属性。
- in:用于迭代类型或键。in后面必须是联合类型,或经过keyof处理的类型,keyof处理后的类型也是联合类型
泛型的语法
- T extends keyof any:T 约束为联合类型(大范围可用,有些实际情况不行,参考Exclude中的示例)
原文地址:https://blog.csdn.net/YUELEI118/article/details/142681978
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!