一、映射类型(Mapped Types)
1、当一个类型基于另一个类型,则需使用映射类型
大部分内置工具通过映射类型来实现
大多数类型体操通过映射类型完成
2、映射类型建立在索引签名的语法上
映射类型是使用了PropertyKeys联合类型的泛型
其中PropertyKeys多是通过keyof创建,然后循环遍历键名创建一个类型
// 映射类型 不能使用interface定义
type MapPerson<Type> = {
[aaa in keyof Type]: Type[aaa]
}
interface IPerson {
name: string
age: number
}
// 拷贝一份Iperson
type NewPerson = MapPerson<IPerson>
3、在使用映射类型时,有两个额外的修饰符
readonly 只读
? 可选
4、通过前缀-、+删除或添加这些修饰符,默认+
type MapPerson<Type> = {
[Property in keyof Type]-?: Type[Property]
}
interface IPerson {
name: string
age?: number
readonly height: number
address?: string
}
type IPersonRequired = MapPerson<IPerson>
// 拷贝的类型少了?属性
二、条件类型和类型工具
1、条件类型用来帮助我们描述输入类型和输出类型之间的关系,类似JS三元表达式
SomeType extends OtherType? TrueType: FalseType;
function sum<T exends number | string>(arg1: T, arg2: T): T extends string ? string: number
function sum(arg1: any, arg2: any) {
return arg1 + arg2
}
const res1 = sum(10, 20)
const res2 = sum("a", "b")
2、inter
在条件类型中推断,在true分支里引用该推断结果,比如有一个数组类型,想要获取到一个函数的参数类型和返回值类型
type CalcFnType = (num1: number, num2: number) => number
function foo() {
return "abc"
}
// 传入的必须是个函数
// 返回函数类型
type MyReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => inter R? R: never
// 返回参数类型
type MyParameterType<T extends (...args: any[]) => any> = T extends (...args: infer A) => any? A: never
type CalcReturnType = MyReturnType<CalcFnType>// number
type FooReturnType = MyReturnType<typeof foo>// string
type CalcParameterType = MyParameterType<CalcFnType>// [num1: number, num2: string]
3、分发条件类型
当在泛型中使用条件类型时,如果传入一个联合类型,就会变成分发的
type toArray<T> = T extends any? T[]: never
type NumArray = toArray<number>
type NumAndStrArray = toArray<number|string>
// number[]|string[] 而不是 (number|string)[]
// 分别传入number和string,再将结果合并
4、Partial
用于构造一个Type下面的所有属性都设置为可选的类型
interface IKun {
name: string
age: number
slogan?: string
}
type IKunOptional1 = Partial<IKun>
// 类型体操
type MyPartial<T> = {
[P in keyof T]?: T[P]
}
// IKun都变成可选的
type IKunOptional2 = MyPartial<IKun>
5、Required
所有属性都变成必选
interface IKun {
name: string
age: number
slogan?: string
}
type IKun1 = Required<IKun>
// 类型体操
type MyRequired<T> = {
[P in keyof T]-?: T[P]
}
// IKun都变成可选的
type IKun2 = MyRequired<IKun>
6、Readonly
interface IKun {
name: string
age: number
slogan?: string
}
type IKun1 = Readonly<IKun>
// 类型体操
type MyReadonly<T> = {
readonly [P in keyof T]: T[P]
}
// IKun都变成只读的
type IKun2 = MyReadonly<IKun>
7、Record<Keys, Type>
用于构造一个对象类型,它所有的key(键)都是Keys类型,它所有的value(值)都是Type类型。
interface IKun {
name: string
age: number
slogan?: string
}
// 类型体操
// name | age | slogan
type keys = keyof IKun
type Res = keyof any // => number|string|symbol
// 确实keys一定是可以作为key的联合类型
type MyRecord<Keys extends keyof any, T> = {
[P in Keys]: T
}
type t1 = "上海" | "北京" | "洛杉矶"
type IKuns = MyRecord<t1, IKun>
/**
type IKuns = {
上海: IKun;
北京: IKun;
洛杉矶: IKun;
}
**/
const ikuns: IKuns = {
"上海": {
name: "xxx",
age: 10
},
"北京": {
name: "yyy",
age: 5
},
"洛杉矶": {
name: "zzz",
age: 3
}
}
8、Pick<Type, Keys>
用于构造一个类型,它是从Type类型里面挑了一些属性Keys
interface IKun {
name: string
age: number
slogan?: string
}
type MyPick<T, K extends keyof T> = {
[P in K]: T[P]
}
type IKuns = MyPick<IKun, "slogan"|"name">
9、Omit<Type, Keys>
用于构造一个类型,它是从Type类型里面过滤了一些属性Keys
interface IKun {
name: string
age: number
slogan?: string
}
type MyOmit<T, K extends keyof T> = {
[P in keyof T as P extends K ? never: P]: T[P]
}
type IKuns = MyOmit<IKun, "slogan"|"name">
/*
type IKuns = {
age: number;
}
*/
10、Exclude
排除
type IKun = "sing" | "dance" | "rap"
type MyExclude<T, E> = T extends E? never: T
type IKuns = MyExclude<IKun, "rap">
//type IKuns = "sing" | "dance"
11、Extract
提取
type IKun = "sing" | "dance" | "rap"
type MyExtract<T, E> = T extends E? T: never
type IKuns = MyExtract<IKun, "rap"|"dance">
//type IKuns = "dance" | "rap"