概念
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 可以声明基本类型, 联合类型, 交叉类型, 元组, interface 不行
interface 可以合并重复声明
索引类型
keyof 取某个类型的键, 返回联合类型
泛型约束
extends, 约束泛型变量
映射类型
in
对联合类型遍历
泛型
软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能
体操
Await
Typescript
type MyAwaited<T> = T extends Promise<infer K> ? (K extends Promise<unknown> ? MyAwaited<K> : K) : T
Pick
Typescript
type MyPick<T, K extends keyof T> = { [P in K]: T[P] }
Exclude
Typescript
type MyExclude<T, K extends T> = T extends K ? never : T
First
Typescript
type First<T extends unknown[]> = T extends [infer P, ...unknown[]] ? P : never
Readonly
Typescript
type MyReadonly<T> = { readonly [K in keyof T]: T[K] }
IF
Typescript
type If<C extends boolean, T, F> = C extends true ? T : F
Concat
Typescript
type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U]
Push
Typescript
type Push<T extends unknown[], U> = [...T, U]
Includes
Typescript
type Includes<T extends unknown[], U> = T extends [infer P, ...infer K]
? Equal<P, U> extends true
? true
: Includes<K, U>
: false
Equal
Typescript
type Equal<P, U> = (<T>() => T extends P ? 1 : 2) extends <T>() => T extends U ? 1 : 2 ? true : false
Unshift
Typescript
type Unshift<T extends unknown[], U> = [U, ...T]
Parameters
Typescript
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer K) => any ? K : never
Readonly2
Typescript
type MyReadonly2<T, K extends keyof T = keyof T> = { readonly [R in keyof T]: T[R] } & {
[R in Exclude<keyof T, K>]: T[R]
}
Chainable
Typescript
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
}
DeepReadonly
Typescript
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
TupleToUnion
Typescript
type TupleToUnion<T extends unknown[]> = T[number]
Last
Typescript
type Last<T extends unknown[]> = T extends [...unknown[], infer R] ? R : T[0]
PromiseAll
Typescript
declare function PromiseAll<T extends unknown[]>(
values: readonly [...T]
): Promise<{ [R in keyof T]: T[R] extends Promise<infer P> ? Awaited<P> : T[R] }>
Lookup
Typescript
type Lookup<U, T extends string> = U extends { type: T } ? U : never
Capitalize
Typescript
type MyCapitalize<S extends string> = S extends `${infer P}${infer R}` ? `${Uppercase<P>}${R}` : S
Typescript
// 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
AnyOf
Typescript
// 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
IsNever
Typescript
type IsNever<T> = [T] extends [never] ? true : false
Replace
Typescript
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
ReplaceAll
Typescript
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
Parameters
Typescript
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer R) => any ? R : never
Flatten
Typescript
type Flatten<T extends unknown[]> = T extends [infer R, ...infer P]
? R extends unknown[]
? [...Flatten<R>, ...Flatten<P>]
: [R, ...Flatten<P>]
: []
Absolute
Typescript
type Absolute<T extends number | string | bigint> = `${T}` extends `-${infer R}` ? R : `${T}`
IsUnion
Typescript
type IsUnion<T, P = T> = [T] extends [never] ? false : T extends P ? ([P] extends [T] ? false : true) : false
ReplaceKeys
Typescript
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
PickByType
Typescript
type PickByType<T, U> = { [R in keyof T as T[R] extends U ? R : never]: T[R] }
OmitByType
Typescript
type OmitByType<T, U> = { [R in keyof T as T[R] extends U ? never : R]: T[R] }
StartsWith
Typescript
type StartsWith<T extends string, U extends string> = T extends `${U}${infer _}` ? true : false
EndsWith
Typescript
type EndsWith<T extends string, U extends string> = T extends `${infer _}${U}` ? true : false
PartialByKeys
Typescript
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] }
>
RequiredByKeys
Typescript
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] }
>
IndexOf
Typescript
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
LastIndexOf
Typescript
type LastIndexOf<T extends unknown[], U> = T extends [...infer R, infer P]
? Equal<P, U> extends true
? R['length']
: LastIndexOf<R, U>
: -1
Unique
Typescript
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
MapTypes
Typescript
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]>
Shift
Typescript
type Shift<T> = T extends [infer _, ...infer R] ? R : never
Reverse
Typescript
type Reverse<T> = T extends [...infer R, infer K] ? [K, ...Reverse<R>] : []
TupleToNestedObject
Typescript
type TupleToNestedObject<T, U> = T extends [infer R, ...infer Rest]
? R extends string
? { [K in R]: TupleToNestedObject<Rest, U> }
: U
: U
FlipArguments
Typescript
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
Flip
Typescript
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
}
Subsequence
Typescript
type Subsequence<T extends any[]> = T extends [infer P, ...infer R] ? [...Subsequence<R>] | [P, ...Subsequence<R>] : []
Without
Typescript
// 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>
: []
Zip
Typescript
type Zip<T, U> = T extends [infer P, ...infer R]
? U extends [infer K, ...infer KR]
? [[P, K], ...Zip<R, KR>]
: []
: []
Fibonacci
Typescript
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]>
Chunk
Typescript
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]
Split
Typescript
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]
LengthOfString
Typescript
type LengthOfString<S extends string, U extends string[] = []> = S extends `${infer P}${infer R}`
? LengthOfString<R, [...U, P]>
: U['length']
RequiredKeys
Typescript
type RequiredKeys<T> = keyof { [R in keyof T as T[R] extends Required<T>[R] ? R : never]: never }
Assign
Typescript
type Assign<T extends Record<string, unknown>, U extends unknown[]> = U extends [infer P, ...infer R]
? Assign<Merge<T, P>, R>
: T
TypedGet
Typescript
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]