The first step is to look at the document. From the document, you can see:

The infer declaration, which introduces a variable of the type to be inferred, is now allowed in the extends substatement of conditional types. This inferred type variable can be referenced in the true branch of conditional types. Infer allows multiple variables of the same type to occur.

For example, the following code extracts the return value type of the function type:

type ReturnType<T> = T extends(... args:any[]) => infer R ? R : any;
Copy the code

Infer is a type variable that can be inferred and must be written in the extends true branch.

So obviously what it does is it gets types from types, like the input or output of a function, or the type of a key or value of an object.

Here’s an example:

// Suppose we have a function that is derived from a package
type NoExport = string;

export const func = (param: NoExport) = > {
  return param;
};
Copy the code

Let’s say you wrap this func again

You should declare NoExport as the input, but you will report an error because NoExport has not been globally defined or exported to you using // error: Cannot find name 'NoExport'.ts(2304) const customFunc = (param: NoExport) => { // doing something but type never change return func(param); };Copy the code

So how do you normally declare this param? Of course, we use our infer because we want to get a type from a type

// We need to define this type to get the type of the first argument to the function
type ReturnFirstType<T> = T extends (first: infer U) => unknown ? U : never;
// We use typeof func to get the function type, since func is not explicitly used everywhere
const customFunc = (param: ReturnFirstType<typeof func>) = > {
  // doing something but type never change
  return func(param);
};
Copy the code

What? This is a fake example. Here’s a real example. OK.

Real case: Encapsulate a shockproof useEffect

const useDebounceEffect = (fn: any, dependencies? :any) = > {
  const debounceFn = useCallback(debounce(fn), []);
  useEffect(debounceFn, dependencies);
};
Copy the code

I’m not going to talk about the implementation. I’m going to focus on the type declaration

We can see the types of the two input arguments, we don’t care at all, because it’s type-safe by useEffect, so we just have to say, take it, useEffect

type ReturnFirstType<T> = T extends (first: infer U) => unknown ? U : never;
type ReturnSecondType<T> = T extends (first: unknown, second: infer U) => unknown ? U : never;
const useDebounceEffect = (
  fn: ReturnFirstType<typeofuseEffect>, dependencies? : ReturnSecondType<typeof useEffect>
) = > {
  const constFn = useCallback(debounce(fn), []);
  useEffect(constFn, dependencies);
};
Copy the code