9
头图
Source: https://juejin.cn/post/7052949415350239246
Author: Angus Angus

foreword

Recently, when I was writing React to define variable types, I accidentally clicked on ElementType, and then found this code in node_modules/@types/react/index.d.ts:

image.png

Niu, although I don't understand it too much, but I just think it's pretty awesome.

Google it

But then we googled and found that this is called type filtering on the Internet, which is a practical TS writing method. \
Check out this one 🌰:

 interface Example{
     a:string;
     b:number;
     c:number;
     d:string;
     ...
     
 }
复制代码

We have an interface of Example, but now we want to do something with this interface, and only want to leave properties of type string, so what should we do? You can use our own defined FilterType.

    type newExample = FilterType<Example,string> // {a:string;d:string;...}
复制代码

Let's see how FilterType is implemented:

    type FilterType<Source, Types> = Pick<
      Source, 
      {
        [K in keyof Source]: Source[K] extends Types ? K : never
      }[keyof Source]
    >;
复制代码

analyze

First, let's take a look at several utility types that appear in the code. (Big guy skips directly)

in

in can traverse enumeration types, similar to for...in

type Example = 'a' | 'b' | 'c' | 'd'
type Obj = {
  [T in Example]: string;  // 遍历Example,把每个key都赋值string类型
}
/* 等价于 
  type Obj = {
    a: string;
    b: string;
    c: string;
    d: string;
  }
*/
复制代码

keyof

In the official TS document, it is called index type query operator , which is actually to get the key of the type, similar to Object.keys() Although I don't know if the analogy is correct.

interface Example {
    a: string;
    b: string;
    c: number;
    d: boolean;
}
    
type Keys = keyof Example   // 等价于 type Keys = 'a' | 'b' | 'c' | 'd'
复制代码

Conditional judgment

interface A {
    a:string;
}

interface B extends A {
    b:string;
} 

// B是否继承于A?若是,则为number类型;若不是,则为string类型
type C = B extends A ? number : string  // 等价于 type C = number
复制代码

start dissecting

First look at one 🌰, unveil her veil, no, it's a mask:

type Mask<source,types> = {
    [K in keyof source]:source[K] extends types ? K : never;
}
interface Example{
    name:string;
    height:number
}
type newType = Mask<Example,string> // { name:'name'; height:never}
复制代码

At this time we see a { name:'name'; height:never} , what??? What's the use of this?

Don't worry! Next, let's continue to look at the following example and uncover her coat: \
Let's take a look at a little knowledge point that can be written down in the notebook: Index access interface properties

type person = { 
    name:"Angus";
    height:185;
}["name" | "height"]
复制代码

Equivalent to:

type person = "Angus" | 185
复制代码

Note that when the value is never, it will not be accessible

type person = { 
    name:"Angus";
    height:185;
    girlFriend:never;
}["name" | "height" | "girlFriend"]
复制代码

Equivalent to

type person = "Angus" | 185
复制代码

(singleDog's self-deprecating

So what's the use of knowing the index access interface properties? Check out this one 🌰 to reveal her clothes:

type Clothes<source,types> = {
    [K in keyof source]:source[K] extends types ? K : never;
}[keyof source]

interface Example{
    name:string;
    height:number;
    home:string
}
type newType = Clothes<Example,string> // type newType = "name | home"
复制代码

This way we can get the union type of the type we want. \
In the last step, we uncover * \
hold on , let's take a look at Pick first. \
Pick is to select several types in a type object to form a new type.

interface Angus{
    name:string;
    height:number;
    wight:number;
}
type newAngus = Pick<Angus,'name' | 'height'> //{name:string;height:number}
复制代码

Its implementation:

    type Pick<T,K extends keyof T> = {
        [P in K] : T[P];
    }
复制代码

Then we look at the one on Google 🌰:

type FilterType<Source, Types> = Pick<
      Source, 
      {
        [K in keyof Source]: Source[K] extends Types ? K : never
      }[keyof Source]
    >;
复制代码

Is the toilet open! ! ! Through Pick, we can select the attributes we want.

    {
       [K in keyof Source]: Source[K] extends Types ? K : never
     }[keyof Source]
复制代码

These two lines of code will get the properties we want. Just pass Pick again and you're done. Has it been shown?

expand

Then let's take a look at some other tool types in TS.

Omit

Omit(a,b) takes two arguments, the first is the base type you want to edit and the second is the type you want to delete.

    type Person = {
        name:string;
        sex:string;
    }
    type newPerson = Omit<Person,'name'> // {sex:string}
复制代码

See how it works:

    type Omit <T,K extends keyof any> = Pick<T,Exclude<keyof T,K>>;
复制代码

Partial

Partial can quickly turn attributes defined in an interface type into optional (Optional)

    type Person = {
        name:string;
        sex:string;
    }
    type newPerson = Partial<Person> // {name?:string;sex?:string}
复制代码

See how it works :\

    type Partial <T> = {
        [P in keyof T]?: T[P]
    }
复制代码

Exclude

Used to remove the specified type from the type collection.

    type a = string | number
    type newPerson = Exclude<a,string>  //number
复制代码

accomplish:

    type Exclude<T, U> = T extends U ? never : T
复制代码

Readonly

Make all properties of the interface read-only.

    type Person = {
        name:string;
        sex:string;
    }
    type newPerson = Readonly<Person> 
    // type newPerson = {readonly name: string;readonly sex: string;}
复制代码

accomplish:

    type Readonly<T> = { readonly [P in keyof T]: T[P]; }
复制代码

ReturnType

The function of ReturnType is to obtain the return type of function T. \

    type T0 = ReturnType<() => string>; // string 
    type T1 = ReturnType<(s: string) => void>; // void
    type T2 = ReturnType<() => T>; // {} 
    type T3 = ReturnType<() => T>; // number[] 
    type T4 = ReturnType; // any 
    type T5 = ReturnType; // any 
    type T6 = ReturnType; // Error 
    type T7 = ReturnType; // Error
复制代码

accomplish:

    type ReturnType any> = T extends (...args: any) => infer R ? R : any;
复制代码

Parameters

The role of Parameters is to obtain the parameter type of the function T.

type getuserInfo = (user: string) => void
// Parameters<T>的作用是用于获取函数 T 的参数类型。
type ParametersUserInfo = Parameters<getuserInfo>
复制代码

Let me introduce it here first. I am currently a senior, and I will go to Netease next year to move bricks. It is not easy to code words. Just give it a like, thank you.

Epilogue

I'm Lin Sanxin, an enthusiastic front-end rookie programmer. If you are motivated, like the front-end, and want to learn the front-end, then we can make friends and fish together haha, touch the fish group, add me, please note [Si No]

image.png


Sunshine_Lin
2.1k 声望7.1k 粉丝