Skip to content

TypeStript 入门 - 04:各种类型

交叉类型

tsx
//! 交叉类型
interface Person1 {
 handsome: string,
}
interface Person2 {
 high: string,
}

//! 利用&符号将多个类型合并为一个新类型,得到的结果是他们的交集
type P1P2 = Person1 & Person2;
//! 说明:赋值handsome和hight两个属性有且只能同时有这2字段,否则报错
let p: P1P2 = { handsome: '帅', high: '高' }
tsx
interface IPerson1 {
 name: string,
 age: number
}

interface IPerson2 {
 name: number
 age: number
}

type Person = IPerson1 & IPerson2;
let name!: never;
//! 说明:两个属性name之间 string & number 类型为never
let p: Person = { name, age: 11 };

交叉混合类型

tsx
function mixin<T, K>(a: T, b: K): T & K {
 return { ...a, ...b }
}

//! 交叉混合类型
const x = mixin({ name: 'pt' }, { age: 11 })
type xType = typeof x;
/* 
type xType = {
 name: string;
} & {
  age: number;
}
*/

条件类型

基本使用

可以使用extends关键字和三元表达式,实现条件判断

tsx
interface Fish {
 name1: string
}
interface Water {
 name2: string
}
interface Bird {
 name3: string
}
interface Sky {
 name4: string
}

//! 条件类型:基本使用
//! 如果T继承Fish类型,就返回Water类型,否则就返回Sky类型
type Condition<T> = T extends Fish ? Water : Sky;
let con1: Condition<Fish> = { name2: '水' }

//! 条件分发
//! 说明:<type1|type2>分别进行分发,然后联合,此句与下面3句等价
let con2: Condition<Fish | Bird> = { name4: '水' };

type c1 = Condition<Fish>;
type c2 = Condition<Bird>;
type c = c1 | c2

内置条件类型

  • Exclude:排除类型

    tsx
    //1.Exclude: 排除类型
    
    type Exclude<T, U> = T extends U ? never : T;
    //说明:把'1' | '2' | '3' 把 '1' | '2' 排除就只剩'3'类型
    type T1 = Exclude<'1' | '2' | '3', '1' | '2'>
    
    //说明:把Function 排除,就是string|number 类型
    type T2 = Exclude<string | number | (() => void), Function>;
  • Extract抽取类型

    tsx
    //2. Extract 提取类型
    type Extract<T, U> = T extends U ? T : never;
    // 说明:'1' | '2' | '3' 提取 '1' | '2', 类型就是'1' | '2'
    type MyExtract = Extract<'1' | '2' | '3', '1' | '2'>

类型推断:infer

  • ReturnType 返回值类型

    tsx
    function getUser(a: number, b: number) {
     return { name: 'pt', age: 10 }
    }
    
    //! 函数返回值推断: ReturnType
    //! 说明:不知道函数返回值类型,可以通过infer R 占位,如果T 满足(...args: any) => infer R 函数,则返回类型R,否则返回never
    type ReturnType<T> = T extends (...args: any) => infer R ? R : never
    type MyReturn = ReturnType<typeof getUser>
  • Parameters 参数类型

    tsx
    function getUser(a: number, b: number) {
     return { name: 'pt', age: 10 }
    }
    
    //! 函数参数类型推断: Parameters
    //! 说明:同上,不知道参数类型,就用inferR 占位代替
    type Parameters<T> = T extends (...args: infer R) => any ? R : any;
    type MyParams = Parameters<typeof getUser>;
  • ConstructorParameters 构造函数参数类型

    tsx
    //! 构造函数参数类型推断:ConstructorParameters
    class Person {
     constructor(name: string, age: number) { }
    }
    type ConstructorParameters<T> = T extends { new(...args: infer R): any } ? R : never
    type MyConstructor = ConstructorParameters<typeof Person>
  • InstanceType 实例类型

    tsx
    //! 实例类型推断:InstanceType
    type InstanceType<T> = T extends { new(...args: any): infer R } ? R : any
    type MyInstance = InstanceType<typeof Person>

类型推断infer实践

  • 将数组类型转化为联合类型

    tsx
    //! 将数组类型转化为联合类型
    type ElementOf<T> = T extends Array<infer E> ? E : never;
    type TupleToUnion = ElementOf<[string, number, boolean]>;
  • 将两个函数的参数转化为交叉类型

    tsx
    //! 将两个函数的参数转化为交叉类型
    type T1 = { name: string };
    type T2 = { age: number };
    type ToIntersection<T> = T extends ([(x: infer U) => any, (x: infer U) => any]) ? U : never;
    //! 表示要把T1、T2赋予给x,那么x的值就是T1、T2的交集, 最终t3 的类型就是T1&T2
    type t3 = ToIntersection<[(x: T1) => any, (x: T2) => any]>

其他内置类型

Partial: 将属性转化为可选

tsx
//! 1.Partial: 将属性转化为可选
interface Company {
 num: number
}

interface Person {
 name: string,
 age: string,
 company: Company
}

//! 说明:[K in keyof T] 循环T中每个属性,然后添加? 让其属性变成可选。缺点:无法深度变成参数可选
type Partial<T> = { [K in keyof T]?: T[K] };
type PartialPerson = Partial<Person>;

//! 深度所有属性可选
type DeepPartial<T> = {
 //! 如果T[K] 是对象,继续深度partial
 [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]
}
type DeepPartialPerson = DeepPartial<Person>;

Required: 将属性转化为必填

tsx
//! 2.Required: 将属性转化为必填
interface Company {
 num: number
}

interface Person {
 name: string,
 age?: string,
 company: Company
}

type PartialPerson = Partial<Person>;
//! 利用[K in keyof T]-?: T[K],可选符号?前面添加-号即可
type Required<T> = { [K in keyof T]-?: T[K] }
type RequiredPerson = Required<PartialPerson>

Readonly: 将属性转化仅读, 属性循环前面添加readonly 即可

tsx
interface Person {
 name: string,
 age?: string,
 company: Company
}

//3.Readonly: 将属性转化仅读, 属性循环前面添加readonly 即可
type Readonly<T> = { readonly [K in keyof T]: T[K] }
type ReadonlyPerson = Readonly<Person>

Pick:在已有属性中,挑选所需的属性

tsx
//4.Pick:在已有属性中,挑选所需的属性
type Pick<T, U extends keyof T> = { [P in U]: T[P] }
type PickPerson = Pick<Person, 'name' | 'age'>

Record: 记录类型

tsx
//! 5.Record: 记录类型
type Record<K extends keyof any, T> = { [P in K]: T }
let person: Record<string, number | string> = { name: 'pt', age: 12 };

//! 6.对象属性和值,映射成Record键值对类型
function map<T extends keyof any, K, U>(obj: Record<T, K>, callback: (item: K, key: T) => U) {
 let result = {} as Record<T, U>
 for (let key in obj) {
  result[key] = callback(obj[key], key)
 }
 return result
}

//const ret: Record<"name" | "age" | "address", string | number>
const ret = map({ name: 'pt', age: 123, address: "sz" }, (item, key) => {
 return item
});

Omit: 忽略对象属性

tsx
//! 7.Omit: 忽略对象属性
let person2 = {
 name: 'pt',
 age: 12,
 address: 'sz'
}
//! 说明:先pick对象属性,然后Exclude在排除不要的,剩下的就是想要的属性。最终把忽略掉的属性过滤掉了
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type OmitAddress = Omit<typeof person2, 'address'>

参考文献

Released under the MIT License.