The introduction

In my last post, I focused on TS ‘keyof, in and infer. This installment will focus on some of the other built-in operators for TS with a pen test.

The operators covered in this issue are as follows:

  • Partial
  • Required
  • Readonly
  • Pick<T,K extends keyof T>
  • Record<K extends keyof any, T>
  • Exclude<T,U>
  • Extract<T,U>
  • Omit<T, K extends keyof any>

First of all, I will describe these advanced operators in TS. If you have mastered them, you can jump to the end of the torn pen test. Hand tear pen test questions

Partial

Partial makes an attribute optional. For example, iUser, the interface name and age are required, but there’s another interface iOptionUser that has exactly the same attributes, except that the name and age are optional. The dumber way, of course, is to write another one by hand.

interface iUser {
  name: string;
  age: number;
}
interfaceiOptionUser { name? :string; age? :number;
}
Copy the code

In fact, what we can see is that iOptionUser is just adding one after the property, right? Interface. We can simply implement the following (this method is built in)

type Partial<T> = {
  [P inkeyof T]? : T[P]; };Copy the code

Required

Required is the opposite of the Partial method, which makes the attribute Required. The method is also very simple and can be implemented like this (the method is built in)

type Required<T> = {
    [P inkeyof T]-? : T[P]; };Copy the code

The effect is as follows:

Readonly

Readonly makes the property read-only. The method is also very simple and can be implemented like this (the method is built in)

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};
Copy the code

The effect is as follows:

Pick<T,K extends keyof T>

Pick, as the name suggests, is to Pick out some attributes. The effect is as follows:

You can think about how to achieve, the official source code is as follows:

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
Copy the code

Record<K extends keyof any, T>

Record is used to create an object with an attribute value of the same type.

type Record<K extends keyof any, T> = {
    [P in K]: T;
};
Copy the code

Exclude<T,U>

Discard all attributes from type T that can be assigned to U, and construct a type. Mainly used for union types.

The official source is as follows:

type Exclude<T, U> = T extends U ? never : T;
Copy the code

Extract<T,U>

Function is the opposite of Exclude

type Extract<T, U> = T extends U ? T : never;
Copy the code

Omit<T, K extends keyof any>

It is used to remove some attributes of an interface. For example, iUser contains the name, age, firstName, lastName, and location attributes, while iUser2 does not contain the location attribute. We can use the aforementioned Pick implementation, but it would be more complicated, so we have the Omit operator.

interface iUser {
    name: string;
    age: number;
    firstName: string;
    lastName: string;
    location: string;
}
interface iUser2 {
    name: string;
    age: number;
    firstName: string;
    lastName: string;
}
Copy the code

The effect is as follows:

Omit code is as follows:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
Copy the code

Hand tear pen test questions

This is a TS test in LeetCode. The original question is a little long, so I will not post it directly. Here is a simplification:

// Suppose there is a type like this: interface initInterface {count: number; message: string; asyncMethod<T, U>(input: Promise<T>): Promise<Action<U>>; syncMethod<T, U>(action: Action<T>): Action<U>; } // After the Connect function, the return type istypeResult { asyncMethod<T, U>(input: T): Action<U>; syncMethod<T, U>(action: T): Action<U>; } // Interface Action<T> {payload? : Ttype// Now we need to write the function type definition of Connect.Copy the code

We need to remove non-function attributes from initInterface and change the signature of the function.

  1. Step 1: Get the function properties
type RemoveNonFunctionProps<T> = {
    [K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];

type FunctionProps = RemoveNonFunctionProps<initInterface>;
Copy the code

type PickFunction<T> = Pick<T, RemoveNonFunctionProps<T>>;
type iFunctionInterface = PickFunction<initInterface>;
Copy the code

Last post

When we compare the function signatures before and after the transformation, we find that only the Promsie of the arguments and the return result is removed.

type asyncMethod<T, U> = (input: Promise<T>) => Promise<Action<U>>;
type transformAsyncMethod<T,U> = (input: T) => Action<U>;
Copy the code

We can do this with infer

type TransformASyncMethod<T> = T extends (
  input: Promise<infer U>
) => Promise<Action<infer S>>
  ? (input: U) = > Action<S>
  : never;
Copy the code

Similarly, let’s look at method 2, before and after the conversion:

type syncMethod<T, U> = (action: Action<T>) => Action<U>;
type transformSyncMethod<T, U> = (action: T) => Action<U>;
Copy the code

We still use infer

type TransformSyncMethod<T> = T extends (
  action: Action<infer U>
) => Action<infer S>
  ? (action: U) = > Action<S>
  : never;
Copy the code

So the conversion function can be written like this:

type TransformMethod<T> = T extends (
  input: Promise<infer U>
) => Promise<Action<infer S>>
  ? (input: U) => Action<S>
  : T extends (action: Action<infer U>) => Action<infer S>
  ? (action: U) => Action<S>
  : never;
Copy the code

4. Now that we have a complete idea of the first three steps, it is time to put the Connect type definition together.

type RemoveNonFunctionProps<T> = {
  [K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];
type PickFunction<T> = Pick<T, RemoveNonFunctionProps<T>>;
type TransformMethod<T> = T extends (
  input: Promise<infer U>
) => Promise<Action<infer S>>
  ? (input: U) = > Action<S>
  : T extends (action: Action<infer U>) => Action<infer S>
  ? (action: U) = > Action<S>
  : never;
type ConnectAll<T> = {
  [K in keyof T]: TransformMethod<T[K]>;
};
type Connect<T> = ConnectAll<PickFunction<T>>;

Copy the code

This time is over here, below is my personal wechat public number.

@Author: WaterMan