如何为高阶函数定义TypeScript类型

作者 happyWang 日期 2023-04-24 Views
如何为高阶函数定义TypeScript类型

高阶函数(HOF)的类型定义一直是 TypeScript 里面相对难度比较高的地方, 而且容易忘记, 所以我打算在这里做一个备忘, 记录一下自己找到或者实现的一些定义

接受的函数和返回的函数的参数一致


const beforeFn =
<F extends (...args: any[]) => any>(fn: F) => (...args: Parameters<F>): ReturnType<F> => {
    console.log('before function:', fn.name);
    return fn(...args);
};

const sum = (a: number, b: number) => a + b;

const beforeSum = beforeFn(sum); 

// declare const beforeSum: (a: number, b: number) => number;

返回的函数比接受的函数多一个参数

From: https://blog.openreplay.com/forever-functional-higher-order-functions-with-typescript/

const demethodize =
  <
  O extends {name: string},
  T extends (...args: any[]) => any
  >(fn: T) =>
  (arg0: O, ...args: Parameters<T>): ReturnType<T> =>
    fn.bind(arg0, ...args)();

const obj = {
    name: 'jack',
    sayHi(question: string) {
        console.log(`Hi, I'm ${this.name}! And ${question}`);
    }
};

const sayHiBySomeOneWithQuestion = demethodize(obj.sayHi);

// declare const sayHiBySomeOneWithQuestion: (arg0: {
//     name: string;
// }, question: string) => void;

返回的函数和接受的函数的只有第一位不一样

interface Rect {}

interface Instance {
    getRect(): Rect;
}

type DropFirst<T extends unknown[]> = T extends [any, ...infer U] ? U : never

function withInst<
  F extends (arg0: Rect, ...args: any[]) => any,
>(fn: F) {
  return (i: Instance, ...args: DropFirst<Parameters<F>>): ReturnType<F> => {
    const r = i.getRect();
    return fn(r, ...args) as ReturnType<F>;
  };
}

const setRectX = (r: Rect, x: number) => {}
const copyRect = (r: Rect, c: Rect) => {}

const setInstX = withInst(setRectX); // declare const setInstX: (i: Instance, x: number) => void;
const copyRectToInst = withInst(copyRect); // declare const copyRectToInst: (i: Instance, c: Rect) => void;