なんのこっちゃというタイトルですが
既存の関数の前後にログを仕込んだ新しい関数を作ったりなど、既存関数のシグネチャを保ったまま、新しい関数を作成したい場合があります。
その場合の型定義のメモです。
サンプル
function withXxxx<T extends any[], U>(
func: (...args: T) => U
): (...args: T) => U {
return function (...args: T) {
return func(...args);
};
}
既存関数の引数を T extends any[]
で表し、戻り値をU
としてそれをそのまま返すようにすれば良いです。
(ラップした関数から既存関数の名前が消えてしまうのがデメリットですが..)
実際の例
前後にログを仕込む関数の場合
function withLogging<T extends any[], U>(
name: string,
func: (...args: T) => U
): (...args: T) => U {
return function (...args: T) {
try {
console.log(`${name}:begin`, ...args)
const returnValue = func(...args);
console.log(`${name}:end`, returnValue)
return returnValue;
} catch (e) {
console.error(`${name}:error`, e)
throw e;
}
};
}
// 2つの引数を加算する関数
function sum(left: number, right: number): number {
return left + right
}
// 可変長引数の引数を加算する関数
function sumAll(...args: number[]): number {
return args.reduce((p, c) => p + c)
}
// 共に元の関数と同一の型定義
const sumLog = withLogging("sum", sum)
const sumAllLog = withLogging("sumAll", sumAll)
console.log(sumLog(4, 2))
// sum:begin 4 2
// sum:end 6
// 6
console.log(sumAllLog(1,2,3,4,5,6,7,8,9,10))
// sumAll:begin 1 2 3 4 5 6 7 8 9 10
// sumAll:end 55
// 55
複数の関数をつなげると処理が追いにくくなるので、使用する場面は限られるかもしれないですが
覚えておくと何かの役に立つと思います。