首页 文章

告诉TypeScript编译器的方法Array.prototype.filter从数组中删除某些类型?

提问于
浏览
6

我试图通过使用Array.prototype.filter从数组中过滤null(undefined)元素,但TypeScript编译器似乎无法识别“过滤器”函数的派生数组并且未能通过类型检查 .

假设遵循简化代码,其中我有一个带有(number | undefined)[]类型的数组,并希望过滤undefined以适合number []数组 .

const arry = [1, 2, 3, 4, "5", 6];
const numArry: number[] = arry
    .map((i) => {
        return typeof i === "number" ? i : void 0;
    })
    .filter((i) => i);

错误说:

类型'(数字|未定义)[]'不能分配给'number []' . 输入'号码| undefined'不能分配给'number'类型 . 类型'undefined'不能分配给'number'类型 .

我可以将结果数组转换为数字[],如下所示,知道过滤器函数删除undefined .

const arry = [1, 2, 3, 4, "5", 6];
const numArry: number[] = (arry
    .map((i) => {
        return typeof i === "number" ? i : void 0;
    })
    .filter((i) => i) as Number[]);

除了铸造之外,还有更好的方法来实现这一目标吗?

环境:TSC2.1启用了strictNullChecks .

4 回答

  • 1

    Solution

    创建一个类型守卫:

    function isDefined<T>(argument: T | undefined): argument is T {
        return argument !== undefined
    }
    

    将它用作类型谓词:

    const foo: number[] = [1, 2, undefined, 4].filter(isDefined)
    

    Explanation

    Array.prototype.filter 有一些重载 . 其中一个知道返回值将取决于您的谓词函数 . 它使用了一个类型后卫:

    filter<S extends T>(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
    

    使用适当的类型保护(而不是采用快捷方式并依赖于隐式强制)可以帮助TypeScript选择此特定的重载 .

  • 5

    使用TypeScrpt的用户定义类型保护功能:

    const arry = [1, 2, 3, 4, "5", 6];
    const numArry: number[] = arry
        .filter((i): i is number => {
            return typeof i === "number";
        });
    // numArry = [1, 2, 3, 4, 6]
    

    在回调函数中查看 i is number . 这个技巧使我们能够转换一种Array.filter结果 .

  • 2

    使用内置的 filter 函数是不可能的,它被声明为返回一个与它接收的类型完全相同的数组 .

    但是,可以定义自己的,完全类型安全的过滤器函数,该函数接受数组和user-defined type guard function,并返回不同类型的数组 .

    不确定有用,但这里是:

    function typeFilter<T, R extends T>(a: T[], f: (e: T) => e is R): R[] {
        const r: R[] = [];
        a.forEach(e => { if (f(e)) r.push(e) });
        return r;
    }
    

    它可以像这样使用:

    const arry = [1, 2, 3, 4, "5", 6];
    
    function isNumber(e): e is number {
        return typeof e === 'number';
    }
    
    const numArry: number[] = typeFilter(arry, isNumber);
    

    不幸的是, isNumber() 必须被定义为单独的显式类型函数,因为编译器不够聪明,无法识别内联函数 e => typeof e === 'number' 也是类型保护 .

  • 3

    map(...) 函数签名是:

    map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
    

    在您的情况下,泛型类型 U 将是: number | undefined

    filter(...) 签名是:

    filter(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[];
    

    由于 T 来自数组接口签名( Array<T> ),因此返回类型将是 value 参数的相同类型的数组(泛型类型 T ) . 在你的情况下 number | undefined .

    这就是你的返回类型是 number | undefined 的原因 .

    基于此,您将需要使用强制转换表达式 . 如果您不想要此行为,则可以删除 --strictNullChecks 标志 .

相关问题