TypeScript design of tool type

Keywords: TypeScript

TypeScript design of tool type

Article directory

Preparatory knowledge

  1. TypeScript advanced type Partial
  2. TypeScript advanced type - condition type (important pre knowledge)
  3. TypeScript advanced types - practical tips

Try to solve an interview question

Original address

The detailed description can be seen in the above link, and only the core points are described here

We have a class of EffectModule. The methods in this class can only have two types of signatures. In addition, there may be some arbitrary non function properties in this class, as follows

interface Action<T> {
  payload?: T;
  type: string;
}

// The signature corresponds to delay
asyncMethod<T, U>(input: Promise<T>): Promise<Action<U>>

// The signature corresponds to setMessage
syncMethod<T, U>(action: Action<T>): Action<U>

class EffectModule {
  count = 1;
  message = "hello!";

  delay(input: Promise<number>) {
    return input.then(i => ({
      payload: `hello ${i}!`,
      type: 'delay'
    });
  }

  setMessage(action: Action<Date>) {
    return {
      payload: action.payload!.getMilliseconds(),
      type: "set-message"
    };
  }
}

Now there is a function called connect, which accepts the instance of EffectModule and turns it into another object. On this object, there is only the method with the same name of EffectModule, but the type signature of the method has been changed, as follows:

asyncMethod<T, U>(input: Promise<T>): Promise<Action<U>>  
//Turned into
asyncMethod<T, U>(input: T): Action<U> 
  
syncMethod<T, U>(action: Action<T>): Action<U>  
//Turned into
syncMethod<T, U>(action: T): Action<U>

The result after connect is:

// Method name, function signature changed
type Connected = {
  delay(input: number): Action<string>
  setMessage(action: Date): Action<number>
}
const effectModule = new EffectModule()
const connected: Connected = connect(effectModule)

The core of this problem is to deduce the Connected type from the EffectModule type.

First, let's analyze the solution steps:

  1. Find function name in EffectModule
  2. Transform function signature
  3. Combining branches to form trunk

The first step is to design a type tool to get the function property name in the object type

// The first two in the preliminary knowledge have been described in detail, which will not be explained here
type FunctionKeys<T> = {
  [K in keyof T]: T[K] extends Function ? K : never
}[keyof T];

In the second step, write out the method types before and after the conversion

type asyncMethod<T, U> = (input: Promise<T>) => Promise<Action<U>> // Before conversion
type asyncMethodConnect<T, U> = (input: T) => Action<U> // After conversion
type syncMethod<T, U> = (action: Action<T>) => Action<U> // Before conversion
type syncMethodConnect<T, U> = (action: T) => Action<U> // After conversion

So how to transform it? We need to use condition type and inference type

// T is the signature of the method in the EffectModule
type EffectModuleMethodsConnect<T> = T extends asyncMethod<infer U, infer V>
	? asyncMethodConnect<U, V>
	: T extends syncMethod<infer U, infer V>
	? syncMethodConnect<U, V>
	: never;
                                                           

Finally, the following results are obtained:

type Connect = (module: EffectModule) => {
  [M in FunctionKeys<EffectModule>]: EffectModuleMethodsConnect<EffectModule[M]>
}

Tool type analysis and design considerations

  1. Master the core knowledge points (generics, index query operators, index accessors, mapping types, conditional types, distributed conditional types, conditional type inference, all of which are included in the preparatory knowledge and can be viewed selectively)
  2. Understand the meaning of the question, make clear the corresponding relationship between "input" and "output", and figure out what we need to do
  3. Disassemble steps, try to combine target results, and deduce unknown results according to known conditions
  4. Try to optimize and merge the steps to find the optimal solution

How to write training tools?

Pay attention to basic knowledge and do more exercises.

Here we give a tool type code base, you can try to read it, and try to write it when you understand it.

utility-types

93 original articles published, 89 praised, 160000 visitors+
Private letter follow

Posted by Azarath on Sun, 02 Feb 2020 22:10:10 -0800