This article takes a brief look at the use and implementation of utility generics. Most of these generic interface definitions are syntactic sugar (shorthand) and can even be found in the typescript package lib.d.ts. The latest version of typescript (2.9) includes most of them. I’ll point out what I didn’t include.
Partial
Partial is used to make an attribute passed in optional. First we need to understand the two keywords keyof and in. Keyof can be used to get all the keys of an object interface. Such as
interface Foo {
name: string;
age: number
}
type T = keyof Foo // -> "name" | "age"
Copy the code
In, on the other hand, can iterate over enumerated types, for example
type Keys = "a" | "b"
type Obj = {
[p in Keys]: any
} // -> { a: any, b: any }
Copy the code
Keyof generates enumerated types, and in uses enumerated types to traverse, so they’re often used together. Look at the Partial source code
type Partial<T> = { [P in keyof T]? : T[P] };Copy the code
Keyof T retrieves the names of all attributes of T, then in iterates, assigning the values to P, and finally T[P] retrieves the values of the corresponding attributes. Student: In the middle? We know what Partial means.
Required
Required makes the attribute passed in mandatory. The source code is shown below
type Required<T> = { [P in keyof T]-? : T[P] };Copy the code
We found an interesting use -? Well, it makes sense to represent the alternatives, right? Remove to make this type mandatory. And that corresponds to a plus, right? This meaning is naturally related to -? Instead, it was used to make properties optional.
Mutable (not included)
Similarly, there are also + and -, and the point here is not to add or subtract between variables but to add or subtract readonly. The following code removes readonly for all attributes of T, or you can write the opposite.
type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
Copy the code
Readonly
Change the attribute passed in to a read-only option, source code below
type Readonly<T> = { readonly [P in keyof T]: T[P] };
Copy the code
Record
Convert the values of all attributes in K to type T
type Record<K extends keyof any, T> = { [P in K]: T };
Copy the code
Pick
Take a set of properties of K from T
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
Copy the code
Exclude
A condition type was introduced in TS 2.8, as shown below
T extends U ? X : Y
Copy the code
If T is a subtype of U, return X, otherwise return Y
You can even combine more than one
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
Conditions are automatically distributed for federated types, such as T extends U? X, Y, T may be A | B type, the actual situation becomes (A extends U? X : Y) | (B extends U ? X : Y)
With that in mind, let’s look at tool generics
Take a look at the Exclude source code
type Exclude<T, U> = T extends U ? never : T;
Copy the code
Combined with the instance
type T = Exclude<1 | 2, 1 | 3> // -> 2
Copy the code
2. Based on the code and examples, we can infer that the function of Exclude is to find out the elements that are not in U from T. In a more semantic way, it is to Exclude U from T
Extract
According to the source code, we infer that Extract is used to Extract T contained in the U element, another more close to the semantics of the statement is to Extract U from T source code as follows
type Extract<T, U> = T extends U ? T : never;
Copy the code
Omit anything
Use the previous combination of Pick and Exclude to realize the function of ignoring some attributes of the object, the source code is as follows
Type Omit = Pick<T, Exclude<keyof T, K>> // Use type Foo = <{name: string, age: number}, 'name'> // -> {age: number }Copy the code
ReturnType
Infer before reading the source code, we need to learn about the keyword infer. In conditional type statements, infer can be used to declare and use a type variable to obtain the return type of a function. The source code is shown below
type ReturnType<T> = T extends ( ... args: any[] ) => infer R ? R : any;Copy the code
Infer R here means to declare a variable to bear the return value type of the signature of the incoming function. In short, infer R is used to fetch the return value type of the function for later use. The specific use
function foo(x: number): Array<number> {
return [x];
}
type fn = ReturnType<typeof foo>;
Copy the code
AxiosReturnType (not included)
Development often uses AXIos to encapsulate API layer requests, usually a function that returns an AxiosPromise
. Now I want to get its Resp type, which we can write based on our knowledge of generics from the last tool.
Import {AxiosPromise} from 'axios' type AxiosReturnType<T> = T extends (... args: any[]) => AxiosPromise<infer R> ? R: any // use type Resp = AxiosReturnType<Api> // pass your Api request function in the generic parameterCopy the code
Refer to the link
- Github.com/Microsoft/T…
- Stackoverflow.com/questions/3…
- www.rickcarlino.com/2017/02/27/…
- Github.com/Microsoft/T… ‘s-new-in-TypeScript#typescript-28
- zhuanlan.zhihu.com/p/39620591