学习TS(10) 类型推断 && 交叉类型 && 条件类型

327 阅读3分钟

「这是我参与2022首次更文挑战的第39天,活动详情查看:2022首次更文挑战」。

赋值推断

赋值时推断,类型从右向左流动,会根据赋值推断出变量类型


let str = "dafei";
let age = 18;
let boolean = true;

返回值推断

自动推断函数返回值类型


function sum(s:string,b:string){
    return a + b;
    // 函数返回值会自动推断出返回值的类型
}
sum("a","b")

函数推断

函数从左到右进行推断


type Sum = (a:string,b:string) => string;
const sum:Sum = (a,b) => a + b;

属性推断

可以通过属性值,推断出属性的类型


let obj = {
    name:'dafei',
    age:18
}
let {name,age} = obj;

类型反推断

可以使用 typeof 关键字进行反推断变量类型

let obj = {
    name:"dafei",
    age:18
}
let obj2 = typeof obj

索引访问操作符

interface IPerson {
    name:string,
    age:number,
    job:{
        address:string
    }
}
type job = IPerson['job']


类型映射


interface IPerson {
    name:string,
    age:number
}
type MapPerson = {[key in keyof IPerson]:IPerson[key]}


交叉类型

交叉类型(Intersection Types)是将多个类型合并为一个类型

举例:我们提供两拨人,一拨人都很帅、另一拨人很高。我们希望找到他们的交叉部分 => 又高又帅的人

interface Person1 {
    handsome: string,
}
interface Person2 {
    high: string,
}
type P1P2 = Person1 & Person2;
let p: P1P2 = { handsome: '帅', high: '高' }


  • 交叉类型
function mixin<T, K>(a: T, b: K): T & K {
    return { ...a, ...b }
}
const x = mixin({ name: 'df' }, { age: 18 })

interface IPerson1 {
    name:string,
    age:number
}

interface IPerson2 {
    name:number
    age:number
}
type person = IPerson1 & IPerson2
let name!:never
let person:person = {name,age:11};  // 两个属性之间 string & number的值为never



条件类型

条件类型的基本使用

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


interface Fish {
    name1: string
}
interface Water {
    name2: string
}
interface Bird {
    name3: string
}
interface Sky {
    name4: string
}
type Condition<T> = T extends Fish ? Water : Sky;
let con1: Condition<Fish> = { name2: '水' }

条件类型分发


let con2: Condition<Fish|Bird> = { name2: '水' } 

这里会用每一项一次进行分发,最终采用联合类型作为结果等价于:

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


内置条件类型

  1. Exclude 排除类型
type Exclude<T, U> = T extends U ? never : T;
type MyExclude = Exclude<'1' | '2' | '3', '1' | '2'>

  1. Extract 抽取类型
type Extract<T, U> = T extends U ? T : never;
type MyExtract = Extract<'1' | '2' | '3', '1' | '2'>

  1. NoNullable 非空检测
type NonNullable<T> = T extends null | undefined ? never : T
type MyNone = NonNullable<'a' | null | undefined>

infer类型推断

  1. ReturnType 返回值类型
function getUser(a: number, b: number) {
  return { name: 'zf', age: 10 }
}
type ReturnType<T> = T extends (...args: any) => infer R ? R : never
type MyReturn = ReturnType<typeof getUser>

  1. Parameters 参数类型
type Parameters<T> = T extends (...args: infer R) => any ? R : any;
type MyParams = Parameters<typeof getUser>;

  1. 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>
  1. InstanceType 实例类型
type InstanceType<T> = T extends { new(...args: any): infer R } ? R : any
type MyInstance = InstanceType<typeof Person>

infer实践

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

type ElementOf<T> = T extends Array<infer E> ? E : never;
type TupleToUnion = ElementOf<[string, number, boolean]>;

将两个函数的参数转化为交叉类型

type T1 = { name: string };
type T2 = { age: number };
type ToIntersection<T> = T extends ([(x: infer U) => any, (x: infer U) => any]) ? U : never;
type t3 = ToIntersection<[(x:T1)=>any,(x:T2)=>any]>

表示要把T1、T2赋予给x,那么x的值就是T1、T2的交集。(参数是逆变的可以传父类)

TS的类型:TS主要是为了代码的安全性来考虑。所以所有的兼容性问题都要从安全性来考虑!