TypeScript常用知识之–条件类型和代理

这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战

因为Typescript的持续火爆,分享下TS的常用知识点,我们一起学习交流,一起加油!

条件类型

  1. 条件类型在Typescript中应用非常广泛,因为他可以自定义出很多的类型推导,很多TS内置的方法都应用了条件类型,下面会一一讲解,

2.条件类型中主要使用的是extends 和 infer

1. extends 的基本使用

1.单一类型

单一类型就是只有单一的类型,有且只有一个类型

2.分布式

拥有几个类型,利用|来分隔

// 单一类型
interface Fish {
    name: string;
}

interface Bird {
    name1: string;
}

interface Water {
    name3: string;
}
interface Sky {
    name4: string;
}

// 如果是Fish的类型就使用water的类型,反之则使用Sky的类型
type C<T> = T extends Fish ? Water : Sky;

let c1: C<Fish> = { name3: "tom" };
let c2: C<Bird> = { name4: "tom" };

//条件类型的分发
interface Shark extends Fish {
    swing: string;
}

interface Sprint extends Water {
    hot: boolean;
}

// 这个会被解析成 C<Shark> | C<Fish>
let c3: C<Shark | Fish> = { name3: "tom" };
let c4: C<Sprint | Water> = { name4: "tom" };
复制代码

2.条件类型的应用

// 找出T中不包括U的部分,利用的是never 和任何类型 | 都是never
type DiffType<T, U> = T extends U ? never : T;
// Diff可以为boolean 也可以为number
let diff1: DiffType<string | boolean | number, string> = true; //boolean
let diff2: DiffType<string | boolean | number, string> = 1; //number

复制代码

3.一些常用的内置类型对extends的使用

// 提取出T中存在U的部分
type Extract<T, U> = T extends U ? T : never;
let extrac: Extract<string | boolean | number, string> = "string";

// 排除null和undefined类型
type NonNullable<T> = T extends null | undefined ? never : T;
let nonNullable1: NonNullable<string | boolean | null> = "string";
let nonNullable2: NonNullable<string | boolean | null> = true;

// 把所有的属性变成可选的
type Partial<T>= {
    [key in keyof T]? : T[key]
}

let partial1:Partial<{a:string,b:boolean}>={a:'1'}
let partial2:Partial<{a:string,b:boolean}>={b:false}
let partial3:Partial<{a:string,b:boolean}>={}

// 把所有的都变成必须的
type Required<T>= {
    [key in keyof T]-? : T[key]
}

let required1:Required<{a?:string,b?:boolean}>={a:'1',b:false}
// let rartial2:Required<{a?:string,b?:boolean}>={b:false} // 报错
// let rartial3:Required<{a?:string,b?:boolean}>={}//报错

// 挑选出k中属于T的属性
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
let pickType:Pick<{a:string,b:boolean},'a'>={a:'1'}


//Record<K,T> K中所有的属性都是T
type Record<K extends keyof any, T> = {
    [P in K]: T;
};
let recordType:Record<'a'|'b'|'c',string>={a:'1',b:'1',c:'1'}

// 元组转联合类型
type ElementOf<T> = T extends Array<infer E> ? E : never;
type TupleType = [string, number];
type ElementOfType = ElementOf<TupleType>;

let elementOfType1: ElementOfType = "s";
let elementOfType2: ElementOfType = 1;

// 深度partial
type DeepPartial<T> = {
    [U in keyof T]?: T[U] extends object ? DeepPartial<T[U]> : T[U];
};

type A ={
    name:string,
    age:number,
    person:{
      hasFeet:boolean,
      hasHair:boolean,
    } 
}

let deepPartialType1:DeepPartial<A> ={
    name:'1',
}
let deepPartialType2:DeepPartial<A> ={
    person:{
      hasFeet:true
    }
}
let deepPartialType3:DeepPartial<A> ={
    age:1,
}
复制代码

4.infer 类型的使用

 // infer 相当于一个定义变量的符合,只要使用了Infer 就可以取到对应的类型
  type Infer<T extends (a:any,b:any)=>any > = T extends (a:string,b:infer P)=>any? P:never
  let infer1:Infer<(a:string, b:number)=> string >= 1
复制代码

5.内置工具对infer 的使用

内置工具对infer的使用非常广泛

 //返回T 中的return 的类型
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
let returnType:ReturnType<(a:string)=>string>='1'

//返回T 中的参数
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
let a = 1;
let parametersType:Parameters<(a:number)=>string>=[a]


//返回构造函数中的参数
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
class Person {
    constructor(public name:string){}
}
let b = 'Tom';
let constructorParametersType:ConstructorParameters<typeof Person>=[b]


//返回实力对象的类型
type InstanceType<T extends abstract new (...args: any) => any> =T extends abstract new (...args: any) => infer R ? R : any;

let person =new Person('tom')
let instanceTypeType:InstanceType<typeof Person>=person;
复制代码

代理

类型在TS中很重要,代理可以把类型通过代理添加一些功能

1. proxy 加代理

any和任何元素组合的都是any类型

type Proxy<T> = {
  get(): T;
  set(value: T): void;
};

type Proxify<T> = {
  [P in keyof T]: Proxy<T[P]>;
};

function proxify<T>(obj: T): Proxify<T> {
  let result: any = <Proxify<T>>{};

  for (const key in obj) {
    type KeyType = typeof key;
    result[key] = {
      get: () => {
        console.log('get',obj[key]);
        return obj[key];
      },
      set: (value: T[KeyType]) => {
        obj[key] = value;
        console.log('set',value);
      },
    };
  }

  return result;
}

type OBJ = {
  name: string;
  age: number;
};

const obj: OBJ = {
  name: "1",
  age: 1,
};

const c: Proxify<OBJ> = proxify<OBJ>(obj);
let name =c1.name // 打印 get 1
c1.name='tom' // 打印 set tom

复制代码

2. unProxify 反代理

利用返代理可以去除掉代理

function unProxify<T>(object: Proxify<T>): T {
    const result: any = <T>{};
    for (const key in object) {
        result[key] = object[key];
    }

    return result;
}

let c1:OBJ=unProxify<OBJ>(c)
复制代码

相关资料

大家喜欢的可以看看我的专栏 (TypeScript常用知识) 我会尽量保持每天晚上更新,如果喜欢的麻烦帮我点个赞,十分感谢

大家如果喜欢“算法”的话,可以看看我分享的另外一个专栏(前端搞算法)里面有更多关于算法的题目的分享,希望能帮助大家更深的理解算法

文章内容目的在于学习讨论与分享学习算法过程中的心得体会,文中部分素材来源网络,如有侵权,请联系删除,邮箱 182450609@qq.com

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享