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.
- 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
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