1.索引类型
学习索引类型 首先要了解keyof(索引查询) Tk 和泛型约束
1.keyof索引查询
就是用来获取某个类型的所有键(键值对的那个键).
interface IPerson {name: string;age: number;
}
type Test = keyof IPerson; //'name'|"age"
这就相当于获得了IPerson里面的键也就是 是name和age。
2.T[K] 索引访问
就是获取接口T的K属性所代表的类型.
interface IPerson {name: string;age: number;
}let type1: IPerson['name']
let type2: IPerson['age']
这样输出的就是string和age了
索引类型就是从对象中抽取一些属性的值 然后拼接成数组
const userInfo = {name: 'lin',age: '18',
}function getValues(userInfo: any, keys: string[]) {return keys.map(key => userInfo[key])
}// 抽取指定属性的值
console.log(getValues(userInfo, ['name','age'])) // ['lin', '18']
// 抽取obj中没有的属性:
console.log(getValues(userInfo, ['sex','outlook'])) // [undefined, undefined]
这个代码的意思就是 定义了一个对象和一个函数
这个函数得两个形参 第一个是任意类型的userInfo对象 第二个就是字符串类型的数组
通过对第二个形参输入的值遍历去寻找到userInfo中相同的属性的值打印出来
即使userinfo中没有这个属性也不会报错 只会输出undefind
3.检查动态属性
const userInfo = {name: 'lin',age: '18',
function getValues<T, K extends keyof T>(userInfo: T, keys: K[]): T[K][] {return keys.map(key => userInfo[key])
}
这个代码的意思是 定义了一个函数 他是有两种可能的类型 T 和 k
T是用来约束userinfo的 k是用来约束keys的
而K泛型继承了 userinfo的属性
所以当我们要调用这个函数时 形参需要输入的属性名是得符合userinfo中的两个属性名 否则就会报错
2.映射类型
TS允许将一个类型映射成另外一个类型1.in
in操作符,用来对联合类型实现遍历。type Person = "name" | "school" | "major"type Obj = {[p in Person]: string
}
2.Partial
Partial<T>将T的索引属性映射为可选的。interface IPerson {name:stringage:number
}
let P1: IPerson = {name:'lin',age:18
}
使用了IPerson接口,就一定要传name和age属性。使用 Partial 改造一下,就可以变成可选属性,interface IPerson {name:stringage:number
}
type IPartial = Partial<IPerson>
let p1: IPartial = {}
Parital 原理Parital 的实现用到了in和keyoftype Partial<T> = {[P in keyof T]?: T[P]
}
[P in keyof T]遍历T 上的所有属性?:设置为属性为可选的T[P]`设置类型为原来的类型3.Readonly
和Partial几乎完全一样Readonly<T>将T的所有属性映射为只读的,例如:/*** Make all properties in T readonly*/
type Readonly<T> = {readonly [P in keyof T]: T[P]
}
[P in keyof T]遍历T`上的所有属性
readonly`设置为属性为可选的
T[P]`设置类型为原来的类型
4.Pick
Pick用于抽取对象子集,挑选一组属性并组成一个新的类型interface IPerson {name:stringage:numbersex:string
}
type IPick = Pick<IPerson.'name' | 'age'>
let p1:IPick = {name:'lin',age:18
}
这样就把name和age从IPerson中抽取出来。5.Record原理
/*** Construct a type with a set of properties K of type T*/
type Record<K extends keyof any, T> = {[P in K]: T
}
Record映射类型有两个参数:第一个参数可以传入继承于uany的任何值。
第二个参数,作为新创建对象的值,被传入。3.条件类型
Exclude和Extrcat的实现就用到了条件类型。1.Exclude
/*** Exclude from T those types that are assignable to U*/
type Exclude<T, U> = T extends U ? never : T
never表示一个不存在的类型never与其他类型的联合后,为其他类型type Test = string | number | never
2.Extract
Extract<T,U>提取联合类型T和联合类型U的所有交集.type Test = Extract<'key1' | 'key2', 'key1'>
/*** Extract from T those types that are assignable to U*/
type Extract<T, U> = T extends U ? T : never
4.工具类型
为了方便开发者使用, TypeScript 内置了一些常用的工具类型。
上文介绍的索引类型、映射类型和条件类型都是工具类型。
1.Omit
Omit<T,U>从类型T中剔除U中的所有属性。interface IPerson {name:stringage:number
}
type IOmit = Omit<IPerson,'age'>
这样就剔除了 IPerson 上的 age 属性。他和pick有点相反 它的原理
type Omit<T, K extends keyof any> =
Pick<T, Exclude<keyof T, K>>
2.NonNullable
NonNullable<T> 用来过滤类型中的 null 及 undefined 类型。type T0 = NonNullable<string | number | undefined>; // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]
原理type NonNullable<T> = T extends null | undefined ?never : T
never 表示一个不存在的类型never与其他类型的联合后,为其他类型3.Parameters
Parameters获取函数的参数类型,将每个参数类型放在一个元祖中。type T1 = Parameters<() => string> // []type T2 = Parameters<(arg: string) => void> // [string]type T3 = Parameters<(arg1: string, arg2: number) => void> // [arg1: string, arg2: number]
Parameters原理
type Parameters<T extends (...args: any) => any> =
T extends (...args: infer P) => any ? P : never
在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用。Parameters首先约束参数T`必须是个函数类型
判断T是否是函数类型,如果是则使用infer P暂时存一下函数的参数类型,后面的语句直接用 P 即可得到这个类型并返回,否则就返回never
4.ReturnTypeReturnType获取函数的返回值类型type T0 = ReturnType<() => string> // stringtype T1 = ReturnType
<(s: string) => void> // void
ReturnType原理/*** Obtain the return type of a function type*/
type ReturnType<T extends (...args: any) => any> =
T extends (...args: any) => infer R ? R : any
懂了 Parameters,也就懂了 ReturnType,
ReturnType首先约束参数T必须是个函数类型
判断T是否是函数类型,如果是则使用infer R暂时存一下函数的返回值类型,后面的语句直接用 R 即可得到这个类型并返回,否则就返回any