Typescript 高级类型
交叉类型
使用 & 合并多个类型:
ts
const mergeFunc = <T, U>(arg1: T, arg2: U): T & U => {
let res = {} as T & U
res = Object.assign(arg1, arg2)
return res
}
mergeFunc({ a: 'a' }, { b: 'b' })const mergeFunc = <T, U>(arg1: T, arg2: U): T & U => {
let res = {} as T & U
res = Object.assign(arg1, arg2)
return res
}
mergeFunc({ a: 'a' }, { b: 'b' })联合类型
使用 | 表示可以是多种类型之一:
ts
type1 | type2 | type3type1 | type2 | type3类型保护
类型谓词
ts
function isString(value: string | number): value is string {
return typeof value === 'string'
}
if (isString(item)) {
console.log(item.length) // 此代码块 item 为 string
}function isString(value: string | number): value is string {
return typeof value === 'string'
}
if (isString(item)) {
console.log(item.length) // 此代码块 item 为 string
}typeof 类型保护
ts
if (typeof item === 'string') {
console.log(item.length)
}if (typeof item === 'string') {
console.log(item.length)
}注意:只能使用 ===/!==,不能使用 includes。只能判断 string/number/boolean/symbol。
instanceof 类型保护
用于检测类的实例。
可以为 null 的类型
开启 --strictNullChecks 后,null 和 undefined 不能赋值给其他类型:
ts
let s = 'foo'
s = null // 报错
let sn: string | null = 'foo'
sn = null // 正常
sn = undefined // 报错,没有 undefinedlet s = 'foo'
s = null // 报错
let sn: string | null = 'foo'
sn = null // 正常
sn = undefined // 报错,没有 undefined类型别名
ts
type TypeString = string
let str: TypeString = 'str'
// 对象别名可在属性中引用自身
type Childs<T> = {
current: T
child?: Childs<T>
}type TypeString = string
let str: TypeString = 'str'
// 对象别名可在属性中引用自身
type Childs<T> = {
current: T
child?: Childs<T>
}注意:类型别名不能使用 extends 和 implements。
字面量类型
ts
type Name = 'wing'
let str: Name = 'wing' // 只能是 'wing'
type Direction = 'north' | 'east' | 'south' | 'west'
function getDirectionFirstLetter(direction: Direction) {
return direction.substr(0, 1)
}type Name = 'wing'
let str: Name = 'wing' // 只能是 'wing'
type Direction = 'north' | 'east' | 'south' | 'west'
function getDirectionFirstLetter(direction: Direction) {
return direction.substr(0, 1)
}可辨识联合
三要素:单例类型属性、联合类型、类型保护:
ts
interface Square { kind: 'square'; size: number }
interface Rectangle { kind: 'rectangle'; height: number; width: number }
interface Circle { kind: 'circle'; radius: number }
type Shape = Square | Rectangle | Circle
function getArea(s: Shape): number {
switch (s.kind) {
case 'square': return s.size * s.size
case 'rectangle': return s.height * s.width
case 'circle': return Math.PI * s.radius ** 2
default: return assertNever(s) // 遗漏分支会报错
}
}
function assertNever(value: never): never {
throw new Error('Unexpected object: ' + value)
}interface Square { kind: 'square'; size: number }
interface Rectangle { kind: 'rectangle'; height: number; width: number }
interface Circle { kind: 'circle'; radius: number }
type Shape = Square | Rectangle | Circle
function getArea(s: Shape): number {
switch (s.kind) {
case 'square': return s.size * s.size
case 'rectangle': return s.height * s.width
case 'circle': return Math.PI * s.radius ** 2
default: return assertNever(s) // 遗漏分支会报错
}
}
function assertNever(value: never): never {
throw new Error('Unexpected object: ' + value)
}多态的 this 类型
ts
class Counter {
constructor(public count: number = 0) {}
public add(value: number) {
this.count += value
return this
}
}
class PowCounter extends Counter {
public pow(value: number) {
this.count = this.count ** value
return this
}
}
new PowCounter(5).add(5).pow(3)class Counter {
constructor(public count: number = 0) {}
public add(value: number) {
this.count += value
return this
}
}
class PowCounter extends Counter {
public pow(value: number) {
this.count = this.count ** value
return this
}
}
new PowCounter(5).add(5).pow(3)索引类型与索引访问
ts
// keyof — 获取所有属性名组成的联合类型
interface Info { name: string; age: number }
let info: keyof Info // 'name' | 'age'
// 索引访问 — 获取属性类型
type NameT = Info['name'] // string
type Values = Info[keyof Info] // string | number(去除 never/null/undefined)// keyof — 获取所有属性名组成的联合类型
interface Info { name: string; age: number }
let info: keyof Info // 'name' | 'age'
// 索引访问 — 获取属性类型
type NameT = Info['name'] // string
type Values = Info[keyof Info] // string | number(去除 never/null/undefined)映射类型
ts
// 遍历属性,添加修饰符
type Readonly<T> = { readonly [P in keyof T]: T[P] }
type Partial<T> = { [P in keyof T]?: T[P] }
type Pick<T, K extends keyof T> = { [P in K]: T[P] }
type Record<K extends keyof any, T> = { [P in K]: T }
// 增加或移除修饰符
type ReadonlyInfo<T> = { +readonly [P in keyof T]-?: T[P] }
// 映射类型推断(包装与拆包)
type Proxy<T> = { get(): T; set(val: T): void }
type Proxify<T> = { [P in keyof T]: Proxy<T[P]> }
function unproxify<T>(t: Proxify<T>): T {
const result = {} as T
for (const k in t) result[k] = t[k].get()
return result
}// 遍历属性,添加修饰符
type Readonly<T> = { readonly [P in keyof T]: T[P] }
type Partial<T> = { [P in keyof T]?: T[P] }
type Pick<T, K extends keyof T> = { [P in K]: T[P] }
type Record<K extends keyof any, T> = { [P in K]: T }
// 增加或移除修饰符
type ReadonlyInfo<T> = { +readonly [P in keyof T]-?: T[P] }
// 映射类型推断(包装与拆包)
type Proxy<T> = { get(): T; set(val: T): void }
type Proxify<T> = { [P in keyof T]: Proxy<T[P]> }
function unproxify<T>(t: Proxify<T>): T {
const result = {} as T
for (const k in t) result[k] = t[k].get()
return result
}条件类型
ts
type Type1<T> = T extends string ? string : number
// 分布式条件类型
type TypeName<T> = T extends string ? string
: T extends number ? number
: T extends boolean ? boolean
: T extends undefined ? undefined
: T extends () => void ? () => void
: object
type Type3 = TypeName<(() => void) | string[]> // 返回联合类型
// Diff:从联合类型中排除
type Diff<T, U> = T extends U ? never : T
type Type2 = Diff<string | number | boolean, undefined | number> // string | booleantype Type1<T> = T extends string ? string : number
// 分布式条件类型
type TypeName<T> = T extends string ? string
: T extends number ? number
: T extends boolean ? boolean
: T extends undefined ? undefined
: T extends () => void ? () => void
: object
type Type3 = TypeName<(() => void) | string[]> // 返回联合类型
// Diff:从联合类型中排除
type Diff<T, U> = T extends U ? never : T
type Type2 = Diff<string | number | boolean, undefined | number> // string | booleaninfer 类型推断
ts
// 获取函数参数类型
type Type11<T> = T extends Array<infer U> ? U : T
type Type9 = Type11<string[]> // string
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any// 获取函数参数类型
type Type11<T> = T extends Array<infer U> ? U : T
type Type9 = Type11<string[]> // string
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any预定义条件类型
| 类型 | 说明 |
|---|---|
Exclude<T, U> | 从 T 剔除可赋值给 U 的类型 |
Extract<T, U> | 提取 T 中可赋值给 U 的类型 |
NonNullable<T> | 从 T 剔除 null 和 undefined |
ReturnType<T> | 获取函数返回值类型 |
InstanceType<T> | 获取构造函数类型的实例类型 |
ts
type T1 = Exclude<'a' | 'b' | 'c', 'b' | 'c'> // 'a'
type T2 = ReturnType<() => string> // string
type T3 = InstanceType<typeof C> // Ctype T1 = Exclude<'a' | 'b' | 'c', 'b' | 'c'> // 'a'
type T2 = ReturnType<() => string> // string
type T3 = InstanceType<typeof C> // CTypeScript 关键词
typeof
获取变量或对象的类型:
ts
const sem: Person = { name: 'hhh', age: 20 }
type Sem = typeof sem // Person
function toArray(x: number): Array<number> { return [x] }
type Func = typeof toArray // (x: number) => Array<number>
const kakuqo = { name: 'kakuqo', address: { province: '北京' } }
type Kakuqo = typeof kakuqo // { name: string; address: { province: string } }const sem: Person = { name: 'hhh', age: 20 }
type Sem = typeof sem // Person
function toArray(x: number): Array<number> { return [x] }
type Func = typeof toArray // (x: number) => Array<number>
const kakuqo = { name: 'kakuqo', address: { province: '北京' } }
type Kakuqo = typeof kakuqo // { name: string; address: { province: string } }const 断言
ts
let x = 'hello' as const // type X = 'hello'
let y = [10, 20] as const // readonly [10, 20]
let z = { text: 'hello' } as const // { readonly text: 'hello' }
// 获取元组元素值的联合类型
type Data = (typeof y)[number]let x = 'hello' as const // type X = 'hello'
let y = [10, 20] as const // readonly [10, 20]
let z = { text: 'hello' } as const // { readonly text: 'hello' }
// 获取元组元素值的联合类型
type Data = (typeof y)[number]keyof
获取对象所有 key 的联合类型:
ts
interface Person { name: string; age: number }
type K1 = keyof Person // 'name' | 'age'
type K2 = keyof Person[] // "length" | "toString" | "pop" | ...
// keyof + typeof
const COLORS = { red: 'red', blue: 'blue' }
type C = keyof typeof COLORS // 'red' | 'blue'interface Person { name: string; age: number }
type K1 = keyof Person // 'name' | 'age'
type K2 = keyof Person[] // "length" | "toString" | "pop" | ...
// keyof + typeof
const COLORS = { red: 'red', blue: 'blue' }
type C = keyof typeof COLORS // 'red' | 'blue'in
遍历枚举类型:
ts
type Keys = 'a' | 'b' | 'c'
type Obj = { [p in Keys]: any } // { a: any, b: any, c: any }type Keys = 'a' | 'b' | 'c'
type Obj = { [p in Keys]: any } // { a: any, b: any, c: any }infer
在条件类型中声明类型变量:
ts
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : anytype ReturnType<T> = T extends (...args: any[]) => infer R ? R : anyextends
泛型约束:
ts
interface ILengthwise { length: number }
function loggingIdentity<T extends ILengthwise>(arg: T): T {
console.log(arg.length)
return arg
}interface ILengthwise { length: number }
function loggingIdentity<T extends ILengthwise>(arg: T): T {
console.log(arg.length)
return arg
}类型收集
React.forwardRef 类型
ts
interface RsRefForwardingComponent<T extends React.ElementType, P = unknown> {
<As extends React.ElementType = T>(
props: React.PropsWithChildren<ReplaceProps<As, WithAsProps<As> & P>>,
context?: any,
): React.ReactElement | null
propTypes?: any
displayName?: string
}
const Button: RsRefForwardingComponent<'button', ButtonProps> = React.forwardRef(...)interface RsRefForwardingComponent<T extends React.ElementType, P = unknown> {
<As extends React.ElementType = T>(
props: React.PropsWithChildren<ReplaceProps<As, WithAsProps<As> & P>>,
context?: any,
): React.ReactElement | null
propTypes?: any
displayName?: string
}
const Button: RsRefForwardingComponent<'button', ButtonProps> = React.forwardRef(...)SafeOmit
解决 Omit 丢失索引签名问题:
ts
type Convert<T> = { [K in keyof T]: string extends K ? never : number extends K ? never : symbol extends K ? never : K }
type Keys<T extends { [x: string]: any; [x: number]: any }> = Convert<T> extends { [_ in keyof T]: infer U } ? U : never
type SafeOmit<T, K extends string | number | symbol> = Exclude<Keys<T>, K> extends keyof T ? Pick<T, Exclude<Keys<T>, K>> : {}type Convert<T> = { [K in keyof T]: string extends K ? never : number extends K ? never : symbol extends K ? never : K }
type Keys<T extends { [x: string]: any; [x: number]: any }> = Convert<T> extends { [_ in keyof T]: infer U } ? U : never
type SafeOmit<T, K extends string | number | symbol> = Exclude<Keys<T>, K> extends keyof T ? Pick<T, Exclude<Keys<T>, K>> : {}
Cao Note