概念
TypeScript 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程
优势
解决大型项目的稳定性, 可维护性
强类型, 支持静态和动态类型
编译期间发现错误
基础类型
boolean
number
string
undefined
null
undefined 和 null 默认是所有类型的子类型
指定 strictNullChecks 之后, 只能只能赋值给自己和 void
any
unknown
安全类型, 类似 any, unknown 类型 无法赋值给其他类型变量
void
never
永远不存在的类型
程序无法运行到(异常)
symbol
数组类型
元组类型
函数类型
interface
interface 是 TS 设计出来用于定义对象类型的,可以对对象的形状进行描述
可选属性
readonly 只读属性
自定义属性(可索引的类型)
类
枚举
高级类型
联合类型
交叉类型
类型别名
与 interface 对比
- 相同点
都可以定义一个对象或函数
都允许继承, interface 使用 extends,type 使用交叉类型实现继承
- 区别
类型别名用于给各种类型定义别名, 更加简洁
type 可以声明基本类型, 联合类型, 交叉类型, 元组, interfa 不行
interface 可以合并重复声明
索引类型
keyof 取某个类型的键, 返回联合类型
泛型约束
extends, 约束泛型变量
映射类型
in
对联合类型遍历
泛型
软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能
体操
Await
ts
type MyAwaited<T> = T extends Promise<infer K> ? (K extends Promise<unknown> ? MyAwaited<K> : K) : T
1
Pick
ts
type MyPick<T, K extends keyof T> = { [P in K]: T[P] }
1
Exclude
ts
type MyExclude<T, K extends T> = T extends K ? never : T
1
First
ts
type First<T extends unknown[]> = T extends [infer P, ...unknown[]] ? P : never
1
Readonly
ts
type MyReadonly<T> = { readonly [K in keyof T]: T[K] }
1
IF
ts
type If<C extends boolean, T, F> = C extends true ? T : F
1
Concat
ts
type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U]
1
Push
ts
type Push<T extends unknown[], U> = [...T, U]
1
Includes
ts
type Includes<T extends unknown[], U> = T extends [infer P, ...infer K]
? Equal<P, U> extends true
? true
: Includes<K, U>
: false
1
2
3
4
5
2
3
4
5
Equal
ts
type Equal<P, U> = (<T>() => T extends P ? 1 : 2) extends <T>() => T extends U ? 1 : 2 ? true : false
1
Unshift
ts
type Unshift<T extends unknown[], U> = [U, ...T]
1
Parameters
ts
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer K) => any ? K : never
1
Readonly2
ts
type MyReadonly2<T, K extends keyof T = keyof T> = { readonly [R in keyof T]: T[R] } & {
[R in Exclude<keyof T, K>]: T[R]
}
1
2
3
2
3
Chainable
ts
type Chainable<T = {}> = {
option: <K extends string, V>(
key: K extends keyof T ? (V extends T[K] ? never : K) : K,
value: V
) => Chainable<Omit<T, K> & { [P in K]: V }>
get: () => T
}
1
2
3
4
5
6
7
2
3
4
5
6
7
DeepReadonly
ts
type DeepReadonly<T> = T extends Object
? {
readonly [R in keyof T]: T[R] extends Object
? T[R] extends Function
? T[R]
: DeepReadonly<T[R]>
: Readonly<T[R]>
}
: never
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
TupleToUnion
ts
type TupleToUnion<T extends unknown[]> = T[number]
1
Last
ts
type Last<T extends unknown[]> = T extends [...unknown[], infer R] ? R : T[0]
1
PromiseAll
ts
declare function PromiseAll<T extends unknown[]>(
values: readonly [...T]
): Promise<{ [R in keyof T]: T[R] extends Promise<infer P> ? Awaited<P> : T[R] }>
1
2
3
2
3
Lookup
ts
type Lookup<U, T extends string> = U extends { type: T } ? U : never
1
Capitalize
ts
type MyCapitalize<S extends string> = S extends `${infer P}${infer R}` ? `${Uppercase<P>}${R}` : S
1
ts
// 1 ways
type UpperLetter =
| 'A'
| 'B'
| 'C'
| 'D'
| 'E'
| 'F'
| 'G'
| 'H'
| 'I'
| 'J'
| 'K'
| 'L'
| 'M'
| 'N'
| 'O'
| 'P'
| 'Q'
| 'R'
| 'S'
| 'T'
| 'U'
| 'V'
| 'W'
| 'X'
| 'Y'
| 'Z'
type KebabCase<S extends string, U = S> = S extends `${infer R}${infer P}`
? R extends UpperLetter
? U extends `${infer _}${infer US}`
? P extends US
? `${Lowercase<R>}${KebabCase<P, S>}`
: `-${Lowercase<R>}${KebabCase<P, S>}`
: S
: `${R}${KebabCase<P, S>}`
: S
// 2 ways
type KebabCase<S extends string> = S extends `${infer R}${infer P}`
? P extends Uncapitalize<P>
? `${Lowercase<R>}${KebabCase<P>}`
: `${Lowercase<R>}-${KebabCase<P>}`
: S
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
AnyOf
ts
// 1 way
type AnyOf<T extends unknown[]> = T extends [infer R, ...infer P]
? R extends [] | '' | false | 0 | Record<string, never>
? AnyOf<P>
: true
: false
// 2 way
type AnyOf<T extends any[]> = T[number] extends 0 | '' | false | [] | { [key: string]: never } ? false : true
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
IsNever
ts
type IsNever<T> = [T] extends [never] ? true : false
1
Replace
ts
type Replace<S extends string, From extends string, To extends string> = From extends ''
? S
: S extends `${infer R}${From}${infer P}`
? `${R}${To}${P}`
: S
1
2
3
4
5
2
3
4
5
ReplaceAll
ts
type ReplaceAll<S extends string, From extends string, To extends string> = From extends ''
? S
: S extends `${infer R}${From}${infer P}`
? `${ReplaceAll<R, From, To>}${To}${ReplaceAll<P, From, To>}`
: S
1
2
3
4
5
2
3
4
5
Parameters
ts
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer R) => any ? R : never
1
Flatten
ts
type Flatten<T extends unknown[]> = T extends [infer R, ...infer P]
? R extends unknown[]
? [...Flatten<R>, ...Flatten<P>]
: [R, ...Flatten<P>]
: []
1
2
3
4
5
2
3
4
5
Absolute
ts
type Absolute<T extends number | string | bigint> = `${T}` extends `-${infer R}` ? R : `${T}`
1
IsUnion
ts
type IsUnion<T, P = T> = [T] extends [never] ? false : T extends P ? ([P] extends [T] ? false : true) : false
1
ReplaceKeys
ts
type ReplaceKeys<U, T, Y> = U extends U
? { [R in keyof U]: R extends T ? (R extends keyof Y ? Y[R] : never) : U[R] }
: never
1
2
3
2
3
PickByType
ts
type PickByType<T, U> = { [R in keyof T as T[R] extends U ? R : never]: T[R] }
1
OmitByType
ts
type OmitByType<T, U> = { [R in keyof T as T[R] extends U ? never : R]: T[R] }
1
StartsWith
ts
type StartsWith<T extends string, U extends string> = T extends `${U}${infer _}` ? true : false
1
EndsWith
ts
type EndsWith<T extends string, U extends string> = T extends `${infer _}${U}` ? true : false
1
PartialByKeys
ts
type Merge<T> = {
[Key in keyof T]: T[Key]
}
type PartialByKeys<T, K = keyof T> = Merge<
{ [R in keyof T as R extends K ? never : R]: T[R] } & { [R in keyof T as R extends K ? R : never]?: T[R] }
>
1
2
3
4
5
6
2
3
4
5
6
RequiredByKeys
ts
type Merge<T> = { [R in keyof T]: T[R] }
type RequiredByKeys<T, K = keyof T> = Merge<
{ [R in keyof T as R extends K ? never : R]: T[R] } & { [R in keyof T as R extends K ? R : never]-?: T[R] }
>
1
2
3
4
2
3
4
IndexOf
ts
type IndexOf<T, U, Res extends unknown[] = []> = T extends [infer P, ...infer R]
? Equal<U, P> extends true
? Res['length']
: IndexOf<R, U, [...Res, P]>
: -1
1
2
3
4
5
2
3
4
5
LastIndexOf
ts
type LastIndexOf<T extends unknown[], U> = T extends [...infer R, infer P]
? Equal<P, U> extends true
? R['length']
: LastIndexOf<R, U>
: -1
1
2
3
4
5
2
3
4
5
Unique
ts
type IndexOf<T, U, Res extends unknown[] = []> = T extends [infer P, ...infer R]
? Equal<U, P> extends true
? Res['length']
: IndexOf<R, U, [...Res, P]>
: -1
type Unique<T, Res extends unknown[] = []> = T extends [infer P, ...infer R]
? IndexOf<Res, P> extends -1
? Unique<R, [...Res, P]>
: Unique<R, Res>
: Res
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
MapTypes
ts
type Include<T, U> = T extends { mapFrom: any; mapTo: any }
? Equal<T['mapFrom'], U> extends true
? T['mapTo']
: never
: never
type MapTypes<T, R extends { mapFrom: any; mapTo: any } | { mapFrom: any; mapTo: any }> = {
[P in keyof T]: Include<R, T[P]> extends never ? T[P] : Include<R, T[P]>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Shift
ts
type Shift<T> = T extends [infer _, ...infer R] ? R : never
1
Reverse
ts
type Reverse<T> = T extends [...infer R, infer K] ? [K, ...Reverse<R>] : []
1
TupleToNestedObject
ts
type TupleToNestedObject<T, U> = T extends [infer R, ...infer Rest]
? R extends string
? { [K in R]: TupleToNestedObject<Rest, U> }
: U
: U
1
2
3
4
5
2
3
4
5
FlipArguments
ts
type Reverse<T> = T extends [...infer R, infer K] ? [K, ...Reverse<R>] : []
type FlipArguments<T extends (...args: any) => any> = T extends (...args: infer R) => infer P
? (...args: Reverse<R>) => P
: never
1
2
3
4
2
3
4
Flip
ts
type Flip<T extends Record<string | number | symbol, any>> = {
[R in keyof T as T[R] extends boolean ? `${T[R]}` : R extends string | number | symbol ? T[R] : never]: R
}
1
2
3
2
3
Subsequence
ts
type Subsequence<T extends any[]> = T extends [infer P, ...infer R] ? [...Subsequence<R>] | [P, ...Subsequence<R>] : []
1
Without
ts
// 1 way
type TupleToUnion<T> = T extends unknown[] ? T[number] : T
type Without<T, U, K = TupleToUnion<U>> = T extends [infer P, ...infer R]
? P extends K
? Without<R, U>
: [P, ...Without<R, U>]
: []
// 2 way
type IndexOf<T, U, Res extends unknown[] = []> = T extends [infer P, ...infer R]
? Equal<U, P> extends true
? Res['length']
: IndexOf<R, U, [...Res, P]>
: -1
type Exist<T, U> = T extends unknown[] ? (IndexOf<T, U> extends -1 ? false : true) : Equal<T, U>
type Without<T, U> = T extends [infer P, ...infer R]
? Exist<U, P> extends false
? [P, ...Without<R, U>]
: Without<R, U>
: []
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Zip
ts
type Zip<T, U> = T extends [infer P, ...infer R]
? U extends [infer K, ...infer KR]
? [[P, K], ...Zip<R, KR>]
: []
: []
1
2
3
4
5
2
3
4
5
Fibonacci
ts
type Fibonacci<
T extends number,
U extends unknown[] = [0],
U1 extends unknown[] = [0],
U2 extends unknown[] = [0]
> = U['length'] extends T ? U1['length'] : Fibonacci<T, [...U, 0], U2, [...U1, ...U2]>
1
2
3
4
5
6
2
3
4
5
6
Chunk
ts
type Chunk<T, U, K extends unknown[] = []> = K['length'] extends U
? [K, ...Chunk<T, U, []>]
: T extends [infer P, ...infer R]
? Chunk<R, U, [...K, P]>
: K['length'] extends 0
? []
: [K]
1
2
3
4
5
6
7
2
3
4
5
6
7
Split
ts
type Split<S extends string, SEP extends string, Res extends string[] = []> = Equal<string, S> extends true
? string[]
: S extends `${infer P}${SEP}${infer R}`
? Split<R, SEP, [...Res, P]>
: SEP extends ''
? [...Res]
: [...Res, S]
1
2
3
4
5
6
7
2
3
4
5
6
7
LengthOfString
ts
type LengthOfString<S extends string, U extends string[] = []> = S extends `${infer P}${infer R}`
? LengthOfString<R, [...U, P]>
: U['length']
1
2
3
2
3
RequiredKeys
ts
type RequiredKeys<T> = keyof { [R in keyof T as T[R] extends Required<T>[R] ? R : never]: never }
1
Assign
ts
type Assign<T extends Record<string, unknown>, U extends unknown[]> = U extends [infer P, ...infer R]
? Assign<Merge<T, P>, R>
: T
1
2
3
2
3
TypedGet
ts
type GetKey<T extends unknown[] | Record<string, any>, K extends string> = T extends unknown[]
? T[0] extends Record<string, unknown>
? T[0][K]
: never
: T extends Record<string, any>
? T[K]
: never
type Get<O extends Record<string, any>, T extends string> = unknown extends O[T]
? T extends `${infer K}.${infer R}`
? R extends string
? O[R] extends unknown
? Get<GetKey<O, K>, R>
: O[R]
: GetKey<O, K>
: T extends string
? GetKey<O, T>
: never
: O[T]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19