在 Typescript 中注释高阶函数
Annotating Higher Order Functions in Typescript
我正在使用一个相当大的 JS 代码库,试图将其迁移到打字稿,但遇到了注释特定高阶函数的问题...
doStuff()
接受 fn1
作为参数并将其包装返回一个新函数,该函数接受 fn1
的第一个参数以外的所有参数。有点像这样:
const fn1 = (arg_1, arg_2, arg_3, arg_n) => { return 'Hello World' }
const doStuff = (fn) => (...args) => {
argument1 = getSomeStuffHere()
return fn(argument1, ...args)
}
const test = doStuff(fn1)
let result = test('arg2', 'arg3', 'arg4')
值得指出的是,有一个 doStuff()
和很多 fnX()
函数,其中包含各种类型组合的各种数量的参数。重要的是正确输入doStuff创建的函数,"any => any"不行!
经过一番折腾,我终于想到了这个:
// just for testing simplified example
type MagicObj = {}
const myMagicObject = {}
type Wrapped<T, R> =
T extends [MagicObj, any, any, any, any] ? (a: T[1], b: T[2], c: T[3], d: T[4]) => R :
T extends [MagicObj, any, any, any] ? (a: T[1], b: T[2], c: T[3]) => R :
T extends [MagicObj, any, any] ? (a: T[1], b: T[2]) => R :
T extends [MagicObj, any] ? (a: T[1]) => R :
T extends [MagicObj] ? () => R :
unknown;
const doStuff = <T extends any[], R>(fn: (...args: T) => R): Wrapped<T, R> => (...args) => fn(myMagicObject, ...args)
// testing examples
const fn1 = (obj: MagicObj, p1: string, p2: boolean, p3: number): string => { return 'Hello World' }
const fn2 = (obj: MagicObj, p1: number, p2: string) => { return 'Hello Mars' }
const fn3 = (obj: MagicObj, p1: boolean) => { return 'Hello The Moon' }
const test1 = doStuff(fn1)
// const test1: (a: string, b: boolean, c: number) => string
let result1 = test1('str', true, 123)
const test2 = doStuff(fn2)
// const test2: (a: number, b: string) => string
let result2 = test2(123, 'str')
const test3 = doStuff(fn3)
// const test3: (a: boolean) => string
let result3 = test3(true)
这似乎有点工作。 VSCodes 类型提示 intellisense 巫术向我展示了示例底部的 test1、2、3 和结果变量的 expect/want,但是 doStuff (...args) => fn(myMagicObject, ...args)
返回的函数,无论我如何尝试对其进行注释,报告 Type '(...args: any[]) => any' is not assignable to type 'Wrapped<T, R>'.ts(2322)
行的错误
知道如何做到这一点吗?
如果我明白你想做什么,我会这样输入 doStuff()
:
const doStuff = <T extends any[], R>(
fn: (magicObject: MagicObj, ...args: T) => R
): ((...args: T) => R) => (...args) => fn(myMagicObject, ...args);
这表示从第一个参数类型为 MagicObj
的任何函数到另一个具有相同类型但删除了 MagicObj
参数的函数的转换。它应该适用于任意数量的参数,通过使用 rest tuples.
这对你有用吗?好的,希望有帮助。祝你好运!
我正在使用一个相当大的 JS 代码库,试图将其迁移到打字稿,但遇到了注释特定高阶函数的问题...
doStuff()
接受 fn1
作为参数并将其包装返回一个新函数,该函数接受 fn1
的第一个参数以外的所有参数。有点像这样:
const fn1 = (arg_1, arg_2, arg_3, arg_n) => { return 'Hello World' }
const doStuff = (fn) => (...args) => {
argument1 = getSomeStuffHere()
return fn(argument1, ...args)
}
const test = doStuff(fn1)
let result = test('arg2', 'arg3', 'arg4')
值得指出的是,有一个 doStuff()
和很多 fnX()
函数,其中包含各种类型组合的各种数量的参数。重要的是正确输入doStuff创建的函数,"any => any"不行!
经过一番折腾,我终于想到了这个:
// just for testing simplified example
type MagicObj = {}
const myMagicObject = {}
type Wrapped<T, R> =
T extends [MagicObj, any, any, any, any] ? (a: T[1], b: T[2], c: T[3], d: T[4]) => R :
T extends [MagicObj, any, any, any] ? (a: T[1], b: T[2], c: T[3]) => R :
T extends [MagicObj, any, any] ? (a: T[1], b: T[2]) => R :
T extends [MagicObj, any] ? (a: T[1]) => R :
T extends [MagicObj] ? () => R :
unknown;
const doStuff = <T extends any[], R>(fn: (...args: T) => R): Wrapped<T, R> => (...args) => fn(myMagicObject, ...args)
// testing examples
const fn1 = (obj: MagicObj, p1: string, p2: boolean, p3: number): string => { return 'Hello World' }
const fn2 = (obj: MagicObj, p1: number, p2: string) => { return 'Hello Mars' }
const fn3 = (obj: MagicObj, p1: boolean) => { return 'Hello The Moon' }
const test1 = doStuff(fn1)
// const test1: (a: string, b: boolean, c: number) => string
let result1 = test1('str', true, 123)
const test2 = doStuff(fn2)
// const test2: (a: number, b: string) => string
let result2 = test2(123, 'str')
const test3 = doStuff(fn3)
// const test3: (a: boolean) => string
let result3 = test3(true)
这似乎有点工作。 VSCodes 类型提示 intellisense 巫术向我展示了示例底部的 test1、2、3 和结果变量的 expect/want,但是 doStuff (...args) => fn(myMagicObject, ...args)
返回的函数,无论我如何尝试对其进行注释,报告 Type '(...args: any[]) => any' is not assignable to type 'Wrapped<T, R>'.ts(2322)
知道如何做到这一点吗?
如果我明白你想做什么,我会这样输入 doStuff()
:
const doStuff = <T extends any[], R>(
fn: (magicObject: MagicObj, ...args: T) => R
): ((...args: T) => R) => (...args) => fn(myMagicObject, ...args);
这表示从第一个参数类型为 MagicObj
的任何函数到另一个具有相同类型但删除了 MagicObj
参数的函数的转换。它应该适用于任意数量的参数,通过使用 rest tuples.
这对你有用吗?好的,希望有帮助。祝你好运!