This is the 16th day of my participation in Gwen Challenge

What is the condition type

A type determined by a conditional expression of the form T extends U? X: Y, that is, if type T can be assigned to type U, the resulting type is type X, otherwise it is type Y.

Conditional types make types non-unique and add flexibility to the language,

Nesting of multiple condition types

type TypeName<T> = T extends string
  ? "string"
  : T extends number
  ? "number"
  : T extends boolean
  ? "boolean"
  : T extends undefined
  ? "undefined"
  : T extends Function
  ? "function"
  : "object";
Copy the code

The code above is a nesting of multiple conditional types, which determines the type of T once and then returns a different string.

type TypeName<T> = T extends string
  ? "string"
  : T extends number
  ? "number"
  : T extends boolean
  ? "boolean"
  : T extends undefined
  ? "undefined"
  : T extends Function
  ? "function"
  : "object";

// Type inferred as a literal type: type T1 = "string"
type T1 = TypeName<string>;
Type T2 = "object"
type T2 = TypeName<string[] >;Copy the code

Distributed condition type

T extends U ? X: Y if the type T is A joint type, such as: (A | B) extends the U? X : Y

The result type, at this point, becomes a combination of multiple condition types,

Can be disassembled into (A extends U? X, Y) | ` ` (extends B U? X, Y)

TypeName

type TypeName<T> = T extends string
  ? "string"
  : T extends number
  ? "number"
  : T extends boolean
  ? "boolean"
  : T extends undefined
  ? "undefined"
  : T extends Function
  ? "function"
  : "object";

/ / type inference for the string and the object literal joint type - the type of T3 = "string" | "object"
type T3 = TypeName<string | string[] >;Copy the code

Diff<T,U> = Exclude<T,U>

Using this feature can help us implement some types of filtering.

type TypeName<T> = T extends string
  ? "string"
  : T extends number
  ? "number"
  : T extends boolean
  ? "boolean"
  : T extends undefined
  ? "undefined"
  : T extends Function
  ? "function"
  : "object";

type Diff<T, U> = T extends U ? never : T;
/ * type inference for the type of T4 = "b" | "c" * /
type T4 = Diff<"a" | "b" | "c"."a" | "e">;
Copy the code

It is first broken down into union types of multiple conditional types

Diff<'a','a' | 'e'> | Diff<'b' ,'a' | 'e'> | Diff<'c' ,'a'|'e'>

  • aCan be assigned to literal union types, – if yes, returnsnever
  • bCan be assigned to literal union types, – no, returnsb
  • cCan be assigned to literal union types, – no, returnsb

The result is: never | | c b

Type of joint is finally never b, c, therefore return | c b

Can be filtered from type T, can be assigned to type U,

We can extend it based on Diff to remove unnecessary types such as undefined and null

NotNull equivalent to NoneNullable<T,U>

type TypeName<T> = T extends string
  ? "string"
  : T extends number
  ? "number"
  : T extends boolean
  ? "boolean"
  : T extends undefined
  ? "undefined"
  : T extends Function
  ? "function"
  : "object";

type Diff<T, U> = T extends U ? never : T;

type NotNull<T> = Diff<T, undefined | null>;
/ * type inference for type T5 = string | number * /
type T5 = NotNull<string | number | undefined | null>;
Copy the code

In fact, these two types are already officially implemented,

type TypeName<T> = T extends string
  ? "string"
  : T extends number
  ? "number"
  : T extends boolean
  ? "boolean"
  : T extends undefined
  ? "undefined"
  : T extends Function
  ? "function"
  : "object";
// Custom type
type Diff<T, U> = T extends U ? never : T;
// Custom type
type NotNull<T> = Diff<T, undefined | null>;

/* Exclude
      
        is the same as Diff
       
         NoneNullable
        
          Extract
         
           from Exclude
          
            Extract
           
             from Exclude
           ,u>
          ,u>
         ,u>
        ,u>
       ,>
      ,u>

Type T6 = "a"
type T6 = Extract<"a" | "b" | "c"."a" | "e">;
Copy the code

ReturnType<()=>{}>

// Can get the type of a function return value
Type T7 = string
type T7 = ReturnType<() = > string>;
Copy the code

Source code and implementation principle

/** * Obtain the return type of a function type */
type ReturnType<T extends(... args:any) = >any> = T extends (
  ...args: any
) => infer R
  ? R
  : any;
Copy the code

The argument T can be assigned to a function that takes any argument and returns an arbitrary value type,

Since the return value type of the function is uncertain, the infer keyword is used to indicate delayed inference, which needs to be determined according to the actual situation.

If the reality is that the return type is R, then the result type is R, otherwise the return value type is any

ReturnType takes a function type and returns the return value type of that function. The key point here is (infer R) that the return value type R is not determined at this point, only in the function

Infer is used to infer numbers after they are executed, which is a delayed inference. In special cases, for example, type T1 = ReturnType

, the type of T1 is any.

Type and interface mostly have the same function, which is to define types. But there are a few small differences:

Type: Instead of creating a new type, just give a name to a given type. Type can also be combined, crossed, and referenced more succinctly.

Interface: Creates a new type. Interfaces can be inherited or merged.