我正在尝试将数组方法filter和map组合成一个名为malter的函数。我到现在为止:
type mapFn<T, S> = (value: T, index: number, originalArray: Readonly<T[]>) => S;
interface Array<T> {
malter<S = any>(mapFn: mapFn<T, S>): S[];
}
function notUndefined<T>(v: T | undefined): v is T {
return typeof v !== "undefined"
}
Array.prototype.malter = function malter<T, S = any>(mapFn: mapFn<T, S>): S[] {
return this.reduce(function(acc: S[], val: T, index: number, orgArr: T[]) {
const el = mapFn(val, index, orgArr);
if (notUndefined(el)) {
acc.push(el);
}
return acc;
}, []);
};
基本上可以。 但是,使用它时,它将在第5-7行中引发TypeError。 另一个隐式返回undefined的测试函数也引发了该错误。
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'."
const test = [2, 3, 4, 5, 3];
function test1(): string[] {
return test.malter<number, string>(num =>
num > 3
? num.toFixed(2)
: undefined
);
}
一个可以节省类型的解决方案是为malter提供2个参数。过滤器和地图函数,分别调用它们。这样可以确保类型的节省,但也可以使其不那么简单。
当然可以在5-7行中做到这一点
(num > 3 ? num.toFixed(2) : undefined) as string
这可能是最好的折衷方案? 你怎么看?有没有我没有想到的解决方案,还是您妥协了?
答案 0 :(得分:2)
@TitianCernicova-Dragomir's answer是正确的,但我也想给出一个略有不同的解决方案。主要区别在于,我们采用{{1}来代替conditional types来将S
(可能包括undefined
)转换成Exclude<S, undefined>
(不包含)。 }作为返回类型(不包含S
),并将输入类型用作undefined
。从调用者的角度来看,它们的行为相同(或几乎如此)(编译器将对输入类型进行自己的类似S | undefined
的分析),但是编译器将可能能够推理出在后一种情况下,Exclude
的实现会更好:
malter
好的,希望能有所帮助。祝你好运!
答案 1 :(得分:1)
您使用undefined
作为要过滤的值。我们可以允许内部函数返回undefined
,然后使用Exclude
将其过滤掉,就像实现一样:
type mapFn<T, S> = (value: T, index: number, originalArray: Readonly<T[]>) => S;
interface Array<T> {
malter<S>(mapFn: mapFn<T, S>): Exclude<S, undefined>[];
}
function notUndefined<T>(v: T | undefined): v is T {
return typeof v !== "undefined"
}
Array.prototype.malter = function malter<T, S>(mapFn: mapFn<T, S>): Exclude<S, undefined>[] {
return this.reduce(function (acc: S[], val: T, index: number, orgArr: T[]) {
const el = mapFn(val, index, orgArr);
if (notUndefined(el)) {
acc.push(el);
}
return acc;
}, []);
};
const test = [2, 3, 4, 5, 3];
function test1(): string[] {
return test.malter(num =>
num > 3
? num.toFixed(2)
: undefined
);
}