Appearance
类型工具
is
is 用于定义变量属于某个类型
下面判断时将出现类型错误提示
const isString = (x: unknown): boolean => typeof x === 'string'
function bm(a: unknown) {
if (isString(a)) {
//error: 对象的类型为 "unknown"。
a.toUpperCase()
}
}
let a = 'ab'
bm(a)
现在重新定义 isString 函数,使用 is 来定义变量为某个类型。
- x is string 表示如果函数返回值为 true,则 x 为 string 类型
const isString = (x: unknown): x is string => typeof x === 'string'
function bm(a: unknown) {
if (isString(a)) {
a.toUpperCase()
}
}
let a = 'ab'
bm(a)
keyof
获取类、接口索引组成的联合类型
- keyof 可用于基本数据类型、any、class、interface、enum 等
任何类型都可以使用 keyof
type BANMASHOU = keyof string
let hj: BANMASHOU = 'match'
索引类型使用 keyof 时,获取索引名
type BANMASHOU = keyof { name: string, age: number }
let hj: BANMASHOU = 'name'
下面是获取对象的属性的函数类型定义
function getAttribute<T>(obj: T, key: keyof T): T[keyof T] {
return obj[key]
}
const user = { name: '斑马兽', age: 18 }
getAttribute(user, 'name')
我们也可以用泛型定义索引类型
function getAttribute<T, D extends keyof T>(obj: T, key: D): T[D] {
return obj[key]
}
const user = { name: '斑马兽', age: 18 }
getAttribute(user, 'name')
typeof
使用 typeof 可获取变量的类型,下面是获取字符串变量的类型
let bm = '斑马兽'
// type BANMASHOU = string
type BANMASHOU = typeof bm
下面使用 typeof 获取对象的
let bm = { name: '斑马兽', age: 18 }
/**
type BANMASHOU = {
name: string;
age: number;
*/
type BANMASHOU = typeof bm
keyof 与 typeof 结合定义获取对象属性的函数
function getAttribute(obj: object, key: string) {
return obj[key as keyof typeof obj]
}
const bm = { name: 'banmashou' }
getAttribute(bm, 'name')
in
in 用于遍历接口或联合类型的属性
- K in keyof T 指 K 类型为 keyof T 获取的 T 类型索引组成的联合类型
type USER = { name: string, age: number }
type MEMBER<T> = {
[K in keyof T]: T[K]
}
const bm: MEMBER<USER & { address: string }> = {
age: 10, name: '斑马兽', address: '上海',
}
extends
extends 在 TS 中拥有多个特性,下面我们来分别了解。
类型继承
extends 实现类型的继承
type HEJUN = { name: string }
interface banmashou extends HEJUN {
age: number
}
const bm: banmashou = { age: 23, name: '斑马兽' }
extends 可用于泛型的类型限定,下例中 T 必须包含 id、render 属性,即 T 类型可赋予 extends 右侧类型
function banmashou<T extends { id: number; render(n: number): number }>(arr: T[]) {
arr.map((a) => a.render(a.id))
}
banmashou([{ id: 1, render(n) { return n } }])
类型条件判断
extends 用于条件判断来决定返回什么类型,A extends B ? true:false
。如果 A(狭窄类型) 可以赋予 B(宽泛类型) 类型则为 true。
- 下例的 bm 变量值必须为 false,因为 BANMASHOU 不包含 HEJUN 类型
type HEJUN = { name: string, age: number }
type BANMASHOU = { name: string }
type BMCMS = BANMASHOU extends HEJUN ? true : false
const bm: BMCMS = false
下面是联合类型的条件判断
type HEJUN = string
type BANMASHOU = string | number
const bm: BANMASHOU extends HEJUN ? string : boolean = false //boolean
const hj: HEJUN extends BANMASHOU ? string : boolean = '斑马兽' //string
根据联合类型过滤掉指定索引
type User = { name: string, age: number, get(): void };
type FilterObjectProperty<T, U> = {
[K in keyof T as Exclude<K, U>]: T[K]
}
type BM = FilterObjectProperty<User, 'name' | 'age'>
过滤掉指定的类型,以下代码含有下面几个含义
- 根据类型获取索引组合成的联合类型
- 根据新的联合类型提取出指定的索引,组合成新的类型
type USER = { name: string, age: number, get(a: string): void }
type FilterProperty<T, U> = {
[K in keyof T]: T[K] extends U ? never : K
}[keyof T]
type UserType = Pick<USER, FilterProperty<USER, Function | number>>
泛型条件分配
如果泛型是普通类型,则与上面一样也是判断左侧类型是否可赋予右侧类型
type HEJUN = string
type BMCMS<T> = T extends HEJUN ? string : boolean
const bm: BMCMS<string> = '斑马兽' //string
如果 extends 是泛型类型,并且传入的类型是联合类型。则分别进行判断,最后得到联合类型。
type HEJUN = string
type BMCMS<T> = T extends HEJUN ? string : boolean
const bm: BMCMS<string | number> = false //string | boolean
条件判断也可以嵌套使用
type HEJUN = string
type BANMASHOU = string | number
type BMCMS<T> =
T extends HEJUN ? string :
T extends BANMASHOU ? symbol : boolean
const bm: BMCMS<string | number> = '斑马兽'
使用**[]**包裹类型,表示使用泛型的整体进行比较
type HEJUN = string | number
type BANMASHOU = string | number
type BMCMS<T> = [T] extends [HEJUN] ? string : boolean
const bm: BMCMS<string | number> = '斑马兽' //string
Exclude
我们利用上面的泛型类型的条件分配,可以创建一个类型用于进行类型的过滤。
- 从 T 泛型类型 中过滤掉 U 的类型
- never 是任何类型的子类型,可以赋值给任何类型,没有类型是 never 的子类型或可以赋值给 never 类型(never 本身除外)
type EXCLUDE<T, U> = T extends U ? never : T
type HEJUN = string
type BANMASHOU = string | number
const bm: EXCLUDE<BANMASHOU, HEJUN> = 100; //number
事实上 typescript 已经提供了 Exclude 关键字用于完成上面的工作,所以我们不需要单独定义 Exclude 类型了。
type HEJUN = string
type BANMASHOU = string | number
const bm: Exclude<BANMASHOU, HEJUN> = 100;
Extract
Extract 与 Exclude 相反,用于获取相交的类型。
type EXTRACT<T, U> = T extends U ? T : never;
type BANMASHOU = string | number | boolean
const bm: EXTRACT<BANMASHOU, string | number> = '斑马兽';
下面是取两个类型相同的属性名
type BANMASHOU = string | number | boolean
const bm: Extract<BANMASHOU, string | number> = '斑马兽';
Pick
pick 可以用于从属性中挑选出一组属性,组成新的类型。
下面定义 pick 类型用于从 BANMASHOU 类型中挑选出 name 与 age 类型。
type BANMASHOU = { name: string, age: number, skill: string }
type PICK<T, U extends keyof T> = {
[P in U]: T[P]
}
type BM = PICK<BANMASHOU, 'name' | 'age'>
const hj: BM = { name: '斑马兽', age: 23 }
同样 typescript 已经原生提供了 Pick 类型,所以我们不用像上面那样自己定义了
type BANMASHOU = { name: string, age: number, skill: string }
type BM = Pick<BANMASHOU, 'name' | 'age'>
const hj: BM = { name: '斑马兽', age: 23 }
Omit
从类型中过滤掉指定属性,这与 Pick 类型工具功能相反
type BM = { name: string, age: number, city: string }
type MyOmit<T, U> = Pick<T, {
[K in keyof T]: K extends U ? never : K
}[keyof T]>
type HJ = MyOmit<BM, 'name' | 'age'> //{city:string}
可以将上面代码使用 Exclude 优化
type BM = { name: string, age: number, city: string }
type MyOmit<T, U> = Pick<T, Exclude<keyof T, U>>
type HJ = MyOmit<BM, 'name' | 'age'> //{city:string}
typescript 已经提供了类型工具 Omit
type BM = { name: string, age: number, city: string }
type HJ = Omit<BM, 'name' | 'age'> //{city:string}
Partial
下面定义 Partial 类型,用于将全部属性设置为可选
type HEJUN = { name: string, age: number }
type PARTIAL<T> = {
[P in keyof T]?: T[P]
}
const bm: PARTIAL<HEJUN> = { name: '斑马兽' } // {name?:string,age?:number}
Typescript 原生提供了 Partial 的支持,所以我们不用自己定义了
type HEJUN = { name: string, age: number }
const bm: Partial<HEJUN> = { name: '斑马兽' }
Record
Record 常用于快速定义对象类型使用
下面我们来手动实现一个 Record,RECORD 类型的第一个参数为索引,第二个为类型
type RECORD<K extends string | number | symbol, V> = {
[P in K]: V
}
type BM = RECORD<'name' | 'age', string | number>
const hj: BM = { name: "斑马兽", age: 18 }
typescript 原生已经提供了 Record 类型,下面定义 MEMBER 类型,索引为字符串,值为任何类型
type BM = Record<'name' | 'age', any>
const hj: BM = { name: "斑马兽", age: 18 }
infer
- infer 只能在 extends 中使用
- infer 的类型变量,只能在 extends 条件的 true 中使用
下面使用 infer 推断属性值类型
type BM = { name: string, age: number }
type AttrType<T> = T extends { name: infer M, age: infer M } ? M : T
type valueType = AttrType<BM> //string | number
下面使用 infer 获取值类型
type USER = { name: string, age: number, get(a: string): void }
type GetType<T> = {
[K in keyof T]: T[K] extends (infer U) ? U : K
}[keyof T]
type valueType = GetType<USER>;
下面是获取函数返回值类型
type BM = (n: string) => number[]
type GetFunctionReturnValue<T> = T extends ((...args: any) => (infer U)[]) ? U : T
type valueType = GetFunctionReturnValue<BM>;