The feed

  1. What are tool generics?
  2. Learning tool generics preconditions?
  3. Learn how to implement official tool generics
  4. Deepen the review
  5. conclusion
  6. The title

After joining the front end team, You Xin realized that his predecessors with rich experience in TS still had many blind spots in TS, so he chose to jump out and learn more in-depth content. Now share with you the tool generics related learning, what is not enough, I hope to communicate with you together. If you don’t want to see it, you can go directly to the official website to learn the official website portal

What are tool generics?

Handle some type specific utility generics, some people also call them utility types because they have some utility properties, like the concept of pure functions.

Learning tool generics preconditions?

Type Type alias

As the name suggests, you can think of it as giving the type a name

type Person = {
  name: string
  age: number
}

const me: Person = {
  name: 'front-end developer'.age: 66,}Copy the code

We can also use it to declare utility generics

type TPickKey<T> = keyof T

interface Person {
  name: string
  age: number
}

const myKey: TPickKey<Person> = 'name'
// TPickKey<Person> = 'name' | 'age'
// This generic takes the key of the incoming type and puts back the associative type of the key
Copy the code

Conditions in the

In TS 2.8, conditional types were added, and the logic is a ternary operator, so it’s easier to understand

T extends U ? X : Y
Copy the code

infer

To declare a variable and use it, see ReturnType below

Extends inheritance

The extends keyword is often used in the following sections. Extends is similar to the concept of a subset in a mathematical set. Check out this article to get a better understanding of TS. Drill into Typescript’s type system

keyof

The keyof operator, introduced in TypeScript 2.1, can be used to retrieve all keys of a type whose return type is a union type.

interface Person {
  name: string
}

type Keys = keyof Person // Keys = "name"
Copy the code

typeof

The typeof operator can be used to get the typeof a variable or object

interface Person {
  name: string
}

const me: Person = {
  name: 'bugaboo'
}
type MyType = typeof me // MyType = Person
type MyNameType = typeof me.name // MyNameType = string
Copy the code

in

Walking through union types allows you to see the implementation mechanism in this article

– (bar)

The Partial Required code can be used to compare Partial Required to Partial Required.

Learn how to implement official tool generics

Before writing complex tool generics, we must master the basic tools and syntax to better understand and implement them.

Please understand the content of the previous section

First let’s look at some common naming rules, refer to herejavaGeneric naming conventions for the

  • E – Element (used extensively by the Java Collections Framename)
  • K – Key
  • N – Number
  • T – Type
  • V – Value
  • S, U, V etc. – 2nd, 3rd, 4th types
  • R – Result
  • A – Accumulator

Partial

Makes the type passed in optional

interface Person {
  name: string
  age: number
}

const you: Person = {
  name: 'yyds'.age: 18,}const me: Partial<Person> = {
  name: 'bugaboo',}// typeof me = {
// name? : string
// age? : number
// }
Copy the code

When I am learning about an unknown thing, I need to understand it as thoroughly as possible. Then will it be traversed deeply?

interface HobbyType {
  title: string
  desc: string
}

interface Person {
  name: string
  age: number
  hobby: HobbyType[]
}

const you: Person = {
  name: 'yyds'.age: 18.hobby: [{ title: 'play game'.desc: 'many games'}}]const me: Partial<Person> = {
  name: 'bugaboo'.hobby: [{}] // Type "{}" lacks the following properties of type "HobbyType" : title, descts(2739)
}
Copy the code

implementation

type MyPartial<T> = {
  [K inkeyof T]? : T[K] }type MyType = MyPartial<{
  name: string
  age: number} >Copy the code

parsing

  1. (type MyPartial<T>First, we declare a utility generic
  2. (K in keyof THere,KRepresents theTType in thekey– traversalT
  3. (T[K]) — get the correspondingkeyThe type of
  4. (? :) — Set it to optional

Readonly

Makes the incoming type read-only

interface Person {
  name: string
}

let me: Readonly<Person> = {
  name: 'bugaboo'
}

me.name = 'yyds' // "name" cannot be assigned because it is read-only. ts(2540)
Copy the code

implementation

type MyReadonly<T> = {
  readonly [K in keyof T]: T[K]
}

type MyType = MyReadonly<{
  name: string} >Copy the code

parsing

  1. (type MyReadonly<T>First, we declare a utility generic
  2. (K in keyof THere,KRepresents theTType in thekey– traversalT
  3. (T[K]) — get the correspondingkeyThe type of
  4. (readonly) — Set it to read-only

Record<K, T>

Apply a type to a union type

interface Person {
  name: string
}

type Peoples = Record<'han' | 'Minority', Person>
// type Peoples = {
// Person: Person
// Minority: Person
// }
Copy the code

The implementation.

type MyRecord<K extends keyof any, T> = {
  [S in K]: T
}

type MyType = MyRecord<'han' | 'minority', { name: ' '} >Copy the code

parsing

  1. (type MyRecordFirst, we declare a utility generic
  2. (<K extends keyof any, T>) — Pass two arguments
  3. (K extends keyof anyKinheritanceany, is free, love to spread what spread what, see my example above, I all spread Chinese.
  4. (S in K– traversalK

Pick<T, S>

In T, filter out types that are not S

interface Person {
  name: string
  age: number
}

type MyType = Pick<Person, 'name'>
// type MyType = {
// name: string
// }
Copy the code

implementation

interface Person {
  name: string
}

type MyPick<T, S extends keyof T> = {
  [K in S]: T[K]
}

type MyType = MyPick<Person, 'name'>
Copy the code

parsing

  1. (type MyPickFirst, we declare a utility generic
  2. (<T, S extends keyof T>) — Pass two arguments
  3. (S extends keyof T) — We talked about it earlierkeyofIs to get the union type, soSIs inheritedTkeyThe type of union composed of values.
  4. (K in S– traversalS
  5. (T[K]– to obtainTThe corresponding type of

Exclude<T, S>

type T = Exclude<1 | 2.2 | 3>
// type T = 1
Copy the code

implementation

type MyExclude<T, S> = T extends S ? never : T
Copy the code

Parsing uses condition types to determine whether T is a subset of S, and then returning never or T automatically distributes conditions for union types

type T = Exclude<1 | 2.2 | 3>
(1 extends 2 | 3 ?  : 2 | 3) | (2 extends 2 | 3 ? never : 2 | 3)
Copy the code

So when a union type is passed in, the complement of the two type sets is returned

Omit<T, K>

Delete the corresponding K in T

interface Person {
  name: string
  age: number
}

type Me = Omit<Person, 'name'>
// type Me = { age: number }
Copy the code

implementation

type MyOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
Copy the code

Parsing uses the above Pick and Exclude combinations

  1. Find the complement firstkeys
  2. And then I’m going to pick it out of the type set.

ReturnType

Gets the type of the return value of the function

function foo(a: string) :Array<string> {
  return [a]
}

type FooReturnType = ReturnType<typeof foo>
// type FooReturnType = string[]
Copy the code

implementation

type MyReturnType<T> = T extends(... arg:any[]) => infer R ? R : any
Copy the code

The infer generation is used to refer to the return type of a function. The extends method is then used to determine whether the function type is a function type, and the corresponding infer generation is returned.

Deepen the review

In fact, I haven’t written all of them. I have only written a few more characteristic tools. The rest, however, is based on a similar implementation with a few tweaks. I’ll list it out, so you can try it out and do it yourself.

  1. Required – Makes all attributes mandatory
// tip: Partial
type MyRequired<T> =  // Imagine for yourself

typeMy = MyRequired<{ name? :string.age: number} >// type My = { name: string }
Copy the code
  1. Extract – Extracts the intersection of two sets of types
// tip: Exclude
type MyExtract<T, K> =  // Imagine

type My = MyExtract<1 | 2.2>
// type My = 2
Copy the code
  1. NonNullable – Removes null and undefined types
// tip: Take advantage of the union type auto-distribution feature of conditional types
type MyNonNullable =  // Imagine

type My = MyNonNullable<string | null | undefined>
// type My = string
Copy the code
  1. Parameters – Gets the line parameter structure type of the function
// tip: Related to ReturnType
type MyParameters<T> = {

}

type My = MyParameters<(arg: { name: string }) = > string>
// type My = [arg: {
// name: string;
// }]
Copy the code

Some of the less common tools, you can go to the official website and learn the official website portal

conclusion

There are a lot of related articles on the Internet, most of them are source code combination analysis, I am also so. However, according to my learning path, I first summarized basic pre-knowledge, such as infer and conditional judgment, and learned and mastered them in a progressive way. I didn’t write all of them, because I hope, through my article, there is always something to gain, can take the rest of the practice. Maybe people will be resistant at the beginning, especially when it is applied to reality, it will test the ability of deconstruction.

The title

  1. Gets the type of an element in a type.
eg: 
  interface Man {
    name: string
    age: number
  }

  typeof age = PickType<Man, 'age'>
  age = number
Copy the code

additional

Official source: github.com/microsoft/T…