introduction
In the last article I focused on the cross-type of ts, this installment will focus on some advanced operators in ts with examples. This article is slightly longer, the author's previous articles are slightly shorter, as a man or to study hard, the article is still long.
The operators covered in this issue are as follows:
- keyof
- in
- infer keyword
- Parameters
- ReturnType
- InstanceType
- ConstructorParameters
- ThisParameterType
- OmitThisParameter
This article is suitable for some basic ts development, if you have not used it at all, please first go to the official website to learn the official documentation,
By learning the above operators, we hope to achieve the following effects:
- No more agonizing over the ts definition written by the big guy
- Looking at source code definitions is no longer difficult
- Your own ts code is smarter, no longer a full screen of any.
Below I will tell you about the advanced operators in ts in combination with specific chestnuts.
keyof
definition
keyof is slightly similar to Object.keys, except that keyof is the keyof the interface, and the keyof is saved as the union type after the key is fetched.
interface iUserInfo {
name: string;
age: number;
}
type keys = keyof iUserInfo;
keyof's simple chestnut
We have a requirement to implement a function getValue to get the value of the object. When we don't touch keyof, we usually write like this:
function getValue(o: object, key: string) {
return o[key];
}
const obj1 = { name: A surname, age: 18 };
const name = getValue(obj1, 'name');
However, writing this way loses the advantages of ts:
- The return value type cannot be determined
- The key cannot be constrained and spelling errors may be made
Here we can use keyof to enhance the type functionality of the getValue function.
After using keyof, we can see that you can complete the prompts that can be entered, and there will be clear prompts when spelling mistakes.function getValue<T extends Object, K extends keyof T> (o: T, key: K) :T[K] {
return o[key];
}
const obj1 = { name: A surname, age: 18 };
const a = getValue(obj1, 'hh');
in
in is used to take the value of the union type. It is mainly used for the construction of arrays and objects.
type name = 'firstName' | 'lastName';
type TName = {
[key in name]: string;
};
const data1 = [
{
a1: 'a',
b1: 'b',
c1: 'c',
d1: 'd',},];const data2 = [
{
a2: 'a',
b2: 'b',},];
But remember not to use the interface, otherwise it will cause an error
infer
First, the official explanation:
Within the extends clause of a conditional type, it is now possible to have infer declarations that introduce a type variable to be inferred. Such inferred type variables may be referenced in the true branch of the conditional type. It is possible to have multiple infer locations for the same type variable.
This translates to:
The infer declaration is now allowed in the extends substatement of conditional types, which introduces a type variable to be inferred. This inferred type variable can be referenced in the true branch of a conditional type. infer allows multiple infer variables of the same type.
Initially, the ts keyword is more restrictive, and the author finds it more difficult to understand, but it is particularly useful for us to get some more complex types. The following key points should be noted during use:
- Occurs only in the extends substatement of a conditional type;
- The infer statement introduces a type variable to be inferred.
- Inferred type variables can be referenced in the true branch of conditional types;
- infer allows multiple infer variables of the same type
A thorough understanding of the use of this keyword must be combined with some examples.
infer instance
Use infer to get the function Parameters
For example, we have defined a function type TArea, and now we want to implement the parameter type of the function to get out, what should we do?
type TArea = (width: number, height: number) => number;
type params = Parameters<TArea>;
In fact, the Parameters method ts has been built in, the source code is as follows:
type Parameters<T extends(... args:any) => any> = T extends(...) args: infer P ) =>any
? P
: never;
Taking a closer look at the above source code, we found four characteristics that infer satisfies following what we said above:
- Occurs only in the extends substatement of a conditional type;
- The infer statement introduces a type variable to be inferred.
- Inferred type variables can be referenced in the true branch of conditional types;
- infer allows multiple infer variables of the same type
Again, since we're getting function arguments, the argument we pass must be a function, so T extends (... args: any) => any. infer appears at the function argument location because we're getting the type of the function argument.
In the same way, the method of getting the return value of the function is ready, and if it still can't be written, forget it.
Use infer to obtain the return value ReturnType
ReturnType Method ts is built-in
type ReturnType<T extends(... args:any) => any> = T extends(...) args:any
) => infer R
? R
: any;
Look at the picture again. Don't call me a liar!
Well, infer is pretty powerful. Let's move on to how infer gets the type of a class instance.
Gets the instance type InstanceType
type InstanceType<T extends new(... args:any) => any> = T extends new(...) args:any
) => infer R
? R
: any;
Between you and me, the smart ts official also has this tool built in.
Gets the constructor type ConstructorParameters
The method ts is built in. Let's take a look at the source code
type ConstructorParameters<
T extends new(... args:any) => any
> = T extends new(... args: infer P) =>any ? P : never;
We can use it like this
Obtain parameter this parameter ThisParameterType
type ThisParameterType<T> = T extends (this: infer U, ... args:any[]) => any
? U
: unknown;
Delete this parameter OmitThisParameter
The results are as follows. You can do it yourself manually, which can train the use of infer well.
The official source code is as follows:type OmitThisParameter<T> = unknown extends ThisParameterType<T>
? T
: T extends(... args: infer A) => infer R ?(... args: A) => R
: T;
We can think of it this way: If the function passed does not contain this argument, it is returned. The following syntax is used to determine whether this parameter is included
unknown extends ThisParameterType<T>
Sum up
We have focused on the advanced use of keyof and infer in ts. We conclude this article with two questions that will be answered in the next article.
Think question 1
This is a leetcode ts pen test question, the original question is slightly long, not directly posted out, here to simplify:
// 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 value type is
type Result {
asyncMethod<T, U>(input: T): Action<U>;
syncMethod<T, U>(action: T): Action<U>;
}
// Where Action
is defined as:
interfaceAction<T> { payload? : Ttype: string
}
// Now it is required to write out the function type definition for Connect.
Think about problem number two
// The original array is as follows const data1 = [{a1:'a',
b1: 'b',
c1: 'c'}]; // Implement a function transformData, pass a keyMap, and return keymap-transformed array const A2 = transformData(data1, {a1:'a2'}); // Return [{a2:'a'}]
const A2 = transformData(data1, { a1: 'a2',b2: 'b1'}); // Return [{a2:'a', b2: 'b'] // Required to be completed with ts, must have perfect type inference, can not appear any
@Author: WaterMan