demand

Now we have a method

function func() {
    //...
}
Copy the code

Let’s add a parameter to it

function func(param: any) {
    //...
}
Copy the code

The return value of this method is the type of the parameter

function func(param: any): (typeof param) {
    // ...
}
Copy the code

Func returns any anyway, because Typeof Param is already evaluated by typescript when it is written, which means typeof Param has actually become a constant any. It doesn’t change because of the param passed in.

The generic

Obviously, we’re going to use generics.

function func<T>(param: any): T {
    // ...
}
Copy the code

If no value is returned, an error will be reported.

function func<T>(param: T): T {
    // ...
    return param;
}
Copy the code

That’s when you find out

const a = func(1); 
Copy the code

We can tell what type a is.

But this is the simplest case, and obviously most of the time we can’t return param directly, we usually need to check the type of param, and then return the corresponding value, and make sure that the return value is of type T.

Limit the scope of

If you want to limit the scope of T, you can use extends;

function func<T extends string>(param: T): T
Copy the code

You can specify the range of T to complex types;

function func<T extends string | number>(param: T): T
Copy the code

At this point, in func, you can narrow param with param as string or param as number.

Returns the return type of the parameter

Sometimes we get more complicated by passing in a param function that may return any value, which means that its type for us is () => any, and we need to make func return the value of this function.

For example, a method called gene: () => number requires that func(gene) be of type number;

First of all, we can refer to the scheme above

function func<T extends () => any>(param: T): T
Copy the code

Then it’s easy. Because of type narrowing, we know that T must be a function. We can use one of Typescript’s tools to ReturnType;

function func<T extends () => any>(param: T): ReturnType<T>
Copy the code

Have a try

function func<T extends () => any>(param: T): ReturnType<T> {
  // ...
  return param();
}
​
const a = func(() => 1);
Copy the code

You can see that a is of type number.

Usage scenarios

Generates an array of generator return values of arbitrary length (I used mockJS here)

function mockRandomList<G extends () => any>(
  min: number,
  max: number,
  generator: G
): Array<ReturnType<G>> {
  return new Array(Random.integer(min, max))
    .fill(undefined)
    .map(() => generator()) as Array<ReturnType<G>>;
}
Copy the code

A generator is a generator that generates an object and then maps multiple objects.

Arrow function

You can also make it an arrow function

const mockRandomList1: <G extends () => any>(
  min: number,
  max: number,
  generator: G
) => ReturnType<G>[] = (min, max, generator) => {
  return new Array(Random.integer(min, max))
    .fill(undefined)
    .map(() => generator());
};
Copy the code

It’s just that you can’t use G inside the function.