可选参数的动态TypeScript签名



不要问为什么我要在Map的子类上实现一个reduce方法:

const nah = Symbol('not-an-arg');
class MapArray<A, B> extends Map<A, B> {
    reduce<T = [A, B]>(f: (prev: T, next: [A, B]) => any, initialVal?: T) {
        let prev = arguments.length > 1 ? arguments[1] : nah;
        for (const [k, v] of this) {
            if (prev === nah) {
                prev = [k, v];
                continue;
            }
            prev = f(prev, [k, v]);
        }
        return prev;
    }
}

它不是最漂亮的东西,但它基本有效。问题是打字。如果我这样做:

new MapArray<string,boolean>().reduce((a,b) => 'whatever');

new MapArray<string,boolean>().reduce((a,b) => 'whatever', []);

我希望它能够捕获第二个参数[]

的类型使用我的无效的版本的TS,我尝试这样做:

 type X = (if initialVal ? typeof initialVal : [A, B])
 reduce<R = any, T = X>(f: (prev: T, next: [A, B]) => R, initialVal?: T);

这显然是完全错误的,但希望你能明白,怀疑这是可能的。有没有人知道我是否可以捕获initialVal的类型,如果它传递,如果没有,默认为[A,B] ?

的问题是:TS操场

它可以编译,但是"a不是可迭代的"(a是reduce回调函数的第一个参数)…A是不可迭代的,因为A是55。

一个解决方案可能是使用undefined代替您的nah和方法重载:

class MapArray<A, B> extends Map<A, B> {
    reduce(f: (prev: [A, B], next: [A, B]) => any): [A, B];
    reduce<T>(f: (prev: T, next: [A, B]) => any, initialVal: T): T;
    reduce<T>(f: (prev: T | [A, B], next: [A, B]) => any, initialVal?: T) {
        let prev: ([A, B] | T | undefined) = initialVal;
        let index = 0;
        for (const [k, v] of this) {
            if (prev === undefined) {
                prev = [k, v];
                continue;
            }
            prev = f(prev, [k, v]);
        }
        return prev;
    }
}
new MapArray<string,boolean>().reduce((a,b) => 'whatever');
new MapArray<string,boolean>().reduce((a,b) => 'whatever', []);

游乐场

我发现这与@Alexander Mills的解决方案非常相似。

这是为了尽可能接近您的原始代码,但我想指出的是,函数f的返回类型应该与prev相同,在这种情况下,示例函数(string "whatever")的返回值不工作。

这并不能100%回答最初的问题,但它可能对某些人有所帮助。

部分解决方案是像这样使用重载:

reduce<R = any>(f: (prev: [A, B], next: [A, B]) => R): R;
reduce<R = any, T = any>(f: (prev: T, next: [A, B]) => R, initialVal?: T) {...}

这不能真正作为OP的答案的原因是,我想获取用户提供的初始val的类型,而不是必须用泛型参数声明它。

再一次,我们要做的是:

reduce<R = any>(f: (prev: [A, B], next: [A, B]) => R): R;
reduce<R = any, T = typeof initialVal>(f: (prev: T, next: [A, B]) => R, initialVal?: <T>) {...}

最新更新