# 高级类型二

WARNING

  • this 类型

  • 索引类型

    • 索引类型查询操作符
    • 索引访问操作符
  • 映射类型

    • 基础
    • 由映射类型进行推断
    • 增加或移除特定修饰符
    • keyof 和映射类型的升级
    • 元祖和数组上的映射类型
  • 条件类型

    • 基础
    • 分布式条件类型
    • 条件类型的类型推断 -- infer
    • 预定义条件类型

this 类型

class Counter {
	constructor(public count: number = 0) {
	}
	add (value: number) {
		this.count += value
		return this
	}
	subtract (value: number) {
		this.count -= value
		return this
	}
}

let counter1 = new Counter(10)
console.log(counter1, 'counter1')
// 链式调用
console.log(counter1.add(3).subtract(2))

class PowCounter extends Counter {
	constructor(public count: number) {
		super(count);
	}
	pow (value: number) {
		this.count = this.count ** value
		return this
	}
}

let powCounter = new PowCounter(2)
console.log(powCounter.pow(3).add(1).subtract(3))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

索引类型: 索引类型查询 keyof,索引类型访问


interface InfoAdvance {
	name: string,
	age: number
}

let infoAd1: keyof InfoAdvance
infoAd1 = 'name'
infoAd1 = 'age'
// infoAd1 = 'sex' // 提示没有这个属性

1
2
3
4
5
6
7
8
9
10
11
function getValue<T, K extends keyof T> (obj: T, names: K[]): T[K][] {
	return names.map(n => obj[n])
}

let infoData = {
	name: 'xiaoyu',
	age: 19
}

let values = getValue(infoData, ['name', 'age'])
console.log(values, 'values---') // ['xiaoyu', 19]
1
2
3
4
5
6
7
8
9
10
11

索引访问操作符 []


interface InfoAdvance2 {
	name: string,
	age: number
}
type NameTypes = InfoAdvance2['name']

1
2
3
4
5
6
7
interface Objs<T> {
	[key: number]: T
}
// keys 是 objs 属性名的类型 keys 为 number
let keys: keyof Objs<number>

1
2
3
4
5
6

映射类型

interface Info1 {
	age: number,
	name: string,
	sex: string
}
// interface ReadOnlyType {
// 	readonly age: number
// }

type ReadOnlyType<T> = {
	readonly [P in keyof T]?: T[P] // 对属性名的遍历
}

// 循环给每个属性都添加 readonly
type ReadOnlyType1 = ReadOnlyType<Info1>
// 所有的属性都添加了 readonly
let info11: ReadOnlyType1 = {
	age: 19,
	name: 'xiaoyu',
	sex: 'nv'
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

TS 内置了Readonly (只读属性) 、Partial (可选属性)

type ReadOnlyType1 = Readonly<Info1>

type ReadOnlyType1 = Partial<Info1>
1
2
3

PickRecord

type Pick<T, K extends keyof T> = {
	[P in K]: T[P]
}
1
2
3
type Record<K extends keyof any, T> = {
    [P in K]: T;
};
1
2
3
interface Info3 {
	name: string,
	age: number,
	address: string
}

let info3: Info3 = {
	name: 'xiaoyu',
	age: 18,
	address: 'beijing'
}
function pickfn<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
	let res: any = []
	keys.map((key) => {
		res[key] = obj[key]
	})
	return res
}

let nameAddress = pickfn(info3, ['name', 'address'])
console.log(nameAddress, 'nameAddress') // [name: 'xiaoyu', address: 'beijing']

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

静态图片

Record 使对象中的每个属性转化成其他值的场景


function mapObj<K extends string | number, T, U> (obj: Record<K, T>, f: (x: T) => U): Record<K, U> {
  let res: any = {}
  for (let key in obj) {
    res[key] = f(obj[key])
  }
  return res
}

let names1 = {
  0: 'hello', // 把 hello 转成了 长度 5
  1: 'world',
  2: 'bye'
}

let lengths = mapObj(names1, (s) => s.length)
console.log(lengths, 'lengths') // {0: 5, 1: 5, 2: 3} 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type Proxy<T> = {
	get(): T;
	set(value: T): void
}

type Proxify <T> = {
	[P in keyof T] : Proxy<T[P]>
}

function proxify<T> (obj: T): Proxify<T> {
	let result = {} as Proxify<T>
	for (let key in obj) {
		result[key] = {
			get: () => obj[key],
			set: (value) => obj[key] = value
		}
	}
	return result
}

let props = {
  name: 'xiaoyu',
  age: 18
}

let proxyProps = proxify(props)
console.log(proxyProps, 'proxyProps')

proxyProps.name.get()
proxyProps.name.set('你好')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

静态图片

逆向拆包

function unproxify <T>(t: Proxify<T>): T {
	let result = {} as T
	for (let k in t) {
		result[k] = t[k].get()
	}
	return result
}
let originProps = unproxify(proxyProps)
console.log(originProps, 'origin') // {name: '你好', age: 18}
1
2
3
4
5
6
7
8
9

增加(+)或移除(-)特定修饰符


interface Info1 {
  age: number,
  name: string,
  sex: string
}
type ReadOnlyType<T> = {
	+readonly [P in keyof T]: T[P] // 对属性名的遍历
}

// 循环给每个属性都添加 readonly
type ReadOnlyType1 = ReadOnlyType<Info1>
let info11: ReadOnlyType1 = {
	age: 19,
	name: 'xiaoyu',
	sex: 'nv'
}

type RemoveReadonlyInfo2 <T> = {
  // -readonly 表示去掉readonly   -? 表示去掉可选符号?
  -readonly [P in keyof T]-?: T[P]
}
// 把所有的readonly去掉
type InfoWithoutReadonly = RemoveReadonlyInfo2<Info1>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

keyof 的升级

const stringIndex = 'a'
const numberIndex = 1
const symbolIndex = Symbol('hh')

type Objs2 = {
	[stringIndex]: string,
	[numberIndex]: number,
	[symbolIndex]: symbol
}

type keysType = keyof Objs2
type ReadonlyTypes <T> = {
	readonly [P in keyof T]: T[P]
}
let objtype3: ReadonlyTypes<Objs2> = {
	a: 'aa',
	1: 11,
	[symbolIndex]: Symbol()
}

// objtype3.a = '00' // 只读属性不可以赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

元祖和数组上的映射类型

type MapToPromise<T> = {
	[K in keyof T]: Promise<T[K]>
}
type Tuple = [number, string, boolean]
type promiseTuple = MapToPromise<Tuple>

let tuple11: promiseTuple = [
	new Promise((resolve) => resolve(1)),
	new Promise((resolve) => resolve('22')),
	new Promise((resolve) => resolve(true)),
]
1
2
3
4
5
6
7
8
9
10
11

unknown 顶级类型

  • 任何类型都可以赋值给 unknown
let value11: unknown
value11 = 1
value11 = '2'
1
2
3
  • 如果没有类型断言或基于控制流的类型细化时,unknown 不可以赋值给其他类型,此时他只能赋值给 unknownany类型
let value22: unknown
// let value33: string = value22 // 提示不能赋值
value11 = value22
1
2
3
  • 如果没有类型断言或基于控制流的类型细化时, 不能在他上面进行任何操作
let value44: unknown
// value44 += 1 // 不能运算
1
2
  • unknown 与其他任何类型组成的交叉类型,最后都等于其他类型
type type1 = string & unknown // string
type type2 = unknown & string[] // string[]
1
2
  • unknown 与任何其他类型(除去 any)组成的联合类型,都等于 unknown 类型
type type3 = unknown | string // unknown
type type4 = any | unknown // any
type type5 = number[] | unknown // unknown
1
2
3
  • neverunknown 的子类型
type type6 = never extends unknown ? true : false // true
1
  • keyof unknown 等于类型 never
type type7 = keyof unknown  // never
1
  • 只能对 unknown 进行等或不等操作
let val1: unknown
let val2: unknown
val1 === val2
val1 !== val2
val1 += val2 // 不能运算
1
2
3
4
5
  • unknown 类型的值不能访问属性,也不能作为函数调用,不能作为类创建实例

let val1 : unknown
val1() // 报错
new val1() // 报错
1
2
3
4
  • 使用映射类型时如果遍历的是 unknown ,则不会映射任何属性
type Types1<T> = {
	[P in keyof T]: number
}
type type8 = Types1<any>
type type9 = Types1<unknown>
1
2
3
4
5

静态图片

静态图片

条件类型 T extends U ? X : Y

type Types2<T> = T extends string ? string : number
let index1: Types2<'a'> // string
let index2: Types2<1> // number
1
2
3

分布式条件类型

当待检测类型是联合类型的时候, 该条件被称为分布式条件类型

type TypeName<T> = T extends any ? T : never
type type10 = TypeName<string | number> // string | number
1
2
type TypeName2<T> =
		T extends string ? string :
		T extends number ? number :
		T extends boolean ? boolean :
		T extends undefined ? unknown : 
          object

type type11 = TypeName2<string[]> // object

1
2
3
4
5
6
7
8
9

分布式条件的应用例子

type Diff<T, U> = T extends U ? never : T
type test = Diff<string | number | boolean, undefined | number> // string | boolean
// string | number | boolean 分别判断是否是 undefined | number 的子类型
// string 是否是 undefined | number 子类型 , 不是 -> 返回 string
// number 是否是 undefined | number 子类型 , 是  -> 返回 never
// boolean 是否是 undefined | number 子类型 , 不是 -> 返回 boolean

1
2
3
4
5
6
7

条件类型和映射类型结合

type type12<T> = {
  [K in keyof  T]: T[K] extends Function ? K : never
} [keyof T] // 返回不为 never的类型

interface Part {
  id: number,
  name: string,
  subparts: Part[],
  undatePart(newName: string): void
}
type Test1 = type12<Part> // undatePart

1
2
3
4
5
6
7
8
9
10
11
12

条件类型的类型推断 infer

// 传进来的如果是数组,就取数组里元素的类型,如果不是数组直接取当前类型
type Type13<T> = T extends any[] ? T[number] : T
type test2 = Type13<string[]> // string
type test3 = Type13<string>


// 使用 infer 
type Type14<T> = T extends Array<infer U> ? U : T
type test4 = Type14<string[]> // string U就是数组元素的类型
type test5 = Type14<number> // number

1
2
3
4
5
6
7
8
9
10
11

预定于内置类型 Exclude<T, U>

type Type15 = Exclude<'a' | 'b' | 'c', 'a' | 'b'> // c
type Type16 = Exclude<'a' | 'b' | 'c', 'a'> // b | c
1
2

Extract<T, U> 选出T中可以赋值给U的类型

type Type17 = Extract<'a' | 'b' | 'c', 'c' | 'b'> // b | c
1

NonNullable<T> 可以从T中去掉 nullundefined

type Type18 = NonNullable<string | number | null | undefined> // string | number
1

ReturnType<T> 获取函数返回值类型

type Type19 = ReturnType<() => string> // string
1

InstanceType<T> 获取构造函数实例类型

// 源码实现
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
1
2

class AClass {
	constructor() {
	}
}

type T1 = InstanceType<typeof AClass>
type T2 = InstanceType<any>
type T3 = InstanceType<never>
type T4 = InstanceType<string> // 报错

1
2
3
4
5
6
7
8
9
10
11