Аннотирование функций высшего порядка в Typescript - PullRequest
0 голосов
/ 03 октября 2019

Я работаю с довольно большой базой кода 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() и LOTS из 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 witchcraft, показывает мне то, что я ожидал / хотел бы для переменных test1, 2, 3 и result в нижней части примера, НО функцию, возвращаемую doStuff (...args) => fn(myMagicObject, ...args), независимо от того, как я пытаюсь это аннотировать,сообщает об ошибке Type '(...args: any[]) => any' is not assignable to type 'Wrapped<T, R>'.ts(2322)

Есть идеи, как это можно сделать?

1 Ответ

1 голос
/ 03 октября 2019

Если я понимаю, что вы пытаетесь сделать, я вместо этого набрал бы doStuff():

const doStuff = <T extends any[], R>(
  fn: (magicObject: MagicObj, ...args: T) => R
): ((...args: T) => R) => (...args) => fn(myMagicObject, ...args);

Это представляет преобразование из любой функции, первый аргумент которой имеет тип MagicObj, в другую. функция того же типа, но с этим удаленным параметром MagicObj. Он должен работать для любого числа параметров, используя кортежи отдыха .

Это работает для вас? Хорошо, надеюсь, это поможет. Удачи!

Ссылка на код

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...