TS中的高级类型:
1.this类型
2.索引类型
- 索引类型查询操作符
- 索引访问操作符
3.映射类型
- 基础
- 由映射类型进行推断
- 增加或移除特定修饰符
4.条件类型
- 基础
- 分布式条件类型
- 条件类型的类型推断-infer
一 this类型
this也可以作为一种类型。
class Counter {
constructor(public count: number = 0){
}
public add(value: number){
this.count += value
return this
}
public subtract(value: number){
this.count -= value
return this
}
}
let count1 = new Counter(10)
console.log(count1.add(2).subtract(4)) //Counter {count: 8}
注意:通过this返回实例,从而实现了链式调用
二 索引类型
1.索引类型查询操作符keyof
连接一个类型,返回一个由这个类型的所有属性名组成的联合类型。
interface Info {
name: string
age: number
}
let info1: keyof Info
info1 = 'name'
info1 = 'age'
// info1 = 'sex' 报错
function getValue<T, K extends keyof T>(obj: T, names: K[]): T[K][] {
return names.map(n=>obj[n])
}
//这里的T[K][]也可以写成Array<T[K]>
const info2 = {
name:'lyy',
age:20
}
let value: (string|number)[] = getValue(info2, ['name', 'age'])
console.log(value) //['lyy', 20]
2.索引访问操作符[]
interface Info {
name: string
age: number
}
type nameType = Info['name'] //这里表示nameType为一个string类型
let name1:nameType = 'lyy---'
console.log(name1) //lyy---
//返回属性值
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
return o[name]
}
//接口类型
interface Objs<T> {
[key: string]:T
}
const objs:Objs<number> = {
age: 18
}
let keys: keyof Objs<number> = objs['age'] //这里的keys类型为string|number
console.log(keys). //18
//注意,索引访问操作符不会返回null/undefined/never类型
interface Types {
a: never
b: string
c: number
d: undefined
e: object
}
type Test = Types[keyof Type] //type Test = string | number | object
三 映射类型
1.根据旧的类型创建出新的类型, 我们称之为映射类型。
看个例子:
interface Info {
age: number
name: string
sex: string
}
如果给所有属性都加readonly,可以用下面的方法:
type ReadonlyType<T> = {
readonly [p in keyof T]: T[p] // 这里的in类似于js中的in,循环
}
type ReadonlyInfo = ReadonlyType<Info>
//type ReadonlyInfo = {
// readonly name: string;
// readonly age: number;
// readonly sex: string;
// }
let info3:ReadonlyInfo = {
age: 18,
name: 'lyy',
sex: 'male',
}
// info3.age = 20 报错,readonly不可修改
ts内置了很多类型, Readonly, Partial, Pick, Record等。
Readonly:添加只读
Partial:添加可选
Pick: 将原有类型中的部分内容映射到新类型中
Record:将一个类型的所有属性值都映射到另一个类型上并创造一个新的类型
type ReadonlyInfo2 = Readonly<Info> //上面的例子可以直接用Readonly
type PartialInfo3 = Partial<Info> //属性置为可选
type testInfo = Partial<Readonly<Info>>; //同时置为只读和可选
Pick例子:
type MyType = Pick<Info, 'name'>;
//type MyType = {
// name: string;
// }
Record例子:
type Animal = 'person' | 'dog' | 'cat';
interface TestInterface {
name: string;
age: number;
}
type testType = Record<Animal, TestInterface>;
let res: testType = {
person: {
name: 'zs',
age: 18
},
dog: {
name: 'wc',
age: 3
},
cat: {
name: 'mm',
age: 2
}
}
console.log(res);
2.拆包
对于 Readonly,Partial 和 Pick 的映射类型, 我们可以对映射之后的类型进行拆包。
还原映射之前的类型, 这种操作我们称之为拆包。
interface TestInterface {
name: string;
age: number;
}
// 增加只读和可选属性
type TestType<T> = {
+readonly [P in keyof T]+?: T[P];
}
type test = TestType<TestInterface>;
//type test = {
// readonly name?: string;
// readonly age?: number;
//}
// 删除只读和可选属性
type UnMyType<T> = {
-readonly [P in keyof T]-?: T[P];
}
type test2 = UnMyType<test>;
四 条件类型
语法: T extends U ? X : Y;
1.简单的条件类型
type Type1<T> = T extends string ? string : number
let type1: Type1<false> //let index: number
2.分布式条件类型
type Type2<T> = T extends any ? T : never
type type2 = Type2<string | number> //type type2 = string | number
比较常用的是类型比较,比如从T中剔除U的类型:
type Diff<T, U> = T extends U ? never : T
type type3 = Diff<string | number | boolean, undefined | number > //type type3 = string | boolean
3.常用的几种类型
TS中已经封装了几种常用的类型:
(1)Exclude:从T中剔除U的类型
上例中可以这么写:
type type3 = Exclude<string | number | boolean, undefined | number >
(2)Extract:提取 T 中可以赋值给 U 的类型
type res = Extract<string | number | boolean, number | string> //type res = string | number
type res1 = Extract<string | boolean, number | string> //type res1 = string
(3)NonNullable: 从T中去掉null和undefined
type type9 = NonNullable<string | number | null | undefined> //type type9 = string | number
(4)ReturnType:获取函数返回值类型
type type10 = ReturnType<()=> string> //type type10 = string
(5)Parameters:获得函数的参数类型组成的元组类型
function say(name: string, age: number, gender: boolean) {
}
type res = Parameters<typeof say>; //type res = [name: string, age: number, gender: boolean]
4.infer关键字
条件类型提供了一个 infer 关键字, 可以让我们在条件类型中定义新的类型
先来看个例子:
定义一个类型, 如果传入的是数组, 就返回数组的元素类型, 如果传入的是普通类型, 则直接返回这个类型。
type Type3<T> = T extends any[] ? T[number] : T
type type4 = Type3<string[]> //type type4 = string 注意这里的T[number]
type type5 = Type3<string> // type type5 = string 注意这里取的是T
如果用infer实现:
type Type4<T> = T extends Array<infer U> ? U : T
type type6 = Type4<string[]>
在条件类型表达式中,可以在 extends 条件语句中使用 infer 关键字来声明一个待推断的类型变量。
infer的作用是让TypeScript自己推断,并将推断的结果存储到一个类型变量中,infer只能用于extends语句中。
// 如果泛型T是()=> infer R的子集,则返回infer R获取到的类型,否则返回boolean
type Func<T> = T extends () => infer R ? R : boolean;
let func1: Func<number>; // boolean;
let func2: Func<''>; // boolean
let func3: Func<() => Promise<number>>; // Promise<number>
再看个例子:
type Obj<T> = T extends {
a: infer VT, b: infer VT } ? VT : number;
let obj1: Obj<string>; // number;
let obj2: Obj<true>; // number;
let obj3: Obj<{
a: string, b: string}>; // string
let obj4: Obj<a: number, b: string>; // string | number
// 当a、b为不同类型时,返回联合类型