Можно ли в машинописном тексте правильно определить типы для полифилла Function.prototype.bind? - PullRequest
0 голосов
/ 06 мая 2020

Мне нужно реализовать полифилл для Function.prototype.bind, что-то вроде этого:

function functionBind(fn, scope, ...bindArgs) {
    return function (...args) {
        const boundArgs = bindArgs || [];
        const callerArgs = Array.prototype.slice.call(arguments) || [];

        return fn.apply(scope, boundArgs.concat(callerArgs));
    };
}

Однако мне трудно реализовать правильные типы для этого. В конце концов, мне понадобится что-то, что принимает параметры данной функции как кортеж, и из этого кортежа мне понадобится тип, который пропускает некоторые записи в начале (в зависимости от того, сколько аргументов предоставлено функции привязки ), чтобы вернуть правильный тип для результирующей функции.

Есть ли способ получить что-то вроде частичного кортежа? Можно ли вообще правильно ввести эту функцию, особенно если включены все строгие параметры компилятора?

1 Ответ

0 голосов
/ 06 мая 2020

Нет хорошего способа извлечь элемент из кортежа (есть рекурсивные решения условного типа, но я бы не обязательно их использовал). Способ bind работает в машинописном тексте (когда --strictBindCallApply включен) - это наличие нескольких перегрузок, до ряда параметров целесообразно привязать:

    bind<T>(this: T, thisArg: ThisParameterType<T>): OmitThisParameter<T>;
    bind<T, A0, A extends any[], R>(this: (this: T, arg0: A0, ...args: A) => R, thisArg: T, arg0: A0): (...args: A) => R;
    bind<T, A0, A1, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1): (...args: A) => R;
    bind<T, A0, A1, A2, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2): (...args: A) => R;
    bind<T, A0, A1, A2, A3, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3): (...args: A) => R;
    bind<T, AX, R>(this: (this: T, ...args: AX[]) => R, thisArg: T, ...args: AX[]): (...args: AX[]) => R;

Вы можете использовать аналогичный подход:

function functionBind<T>(fn: T, thisArg: ThisParameterType<T>): OmitThisParameter<T>;
function functionBind<T, A0, A extends any[], R>(fn: (this: T, arg0: A0, ...args: A) => R, scope: T, arg0: A0): (...args: A) => R;
function functionBind<T, A0, A1, A extends any[], R>(fn: (this: T, arg0: A0, arg1: A1, ...args: A) => R, scope: T, arg0: A0, arg1: A1): (...args: A) => R;
function functionBind<T, A0, A1, A2, A extends any[], R>(fn: (this: T, arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, scope: T, arg0: A0, arg1: A1, arg2: A2): (...args: A) => R;
function functionBind<T, A0, A1, A2, A3, A extends any[], R>(fn: (this: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, scope: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3): (...args: A) => R;
function functionBind<T, AX, R>(fn: (this: T, ...args: AX[]) => R, scope: T, ...args: AX[]): (...args: AX[]) => R;
function functionBind<T>(fn: (this: T, ...args: any[]) => any, scope: T, ...bindArgs: any[]) {
    return function (...args: any[]) {
        const boundArgs = bindArgs || [];
        const callerArgs = Array.prototype.slice.call(arguments) || [];

        return fn.apply(scope, boundArgs.concat(callerArgs));
    };
}

function test(a: string, b: number) {

}

var r = functionBind(test, null, "")  // (b: number) => void

Playground Link

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