我试图通过使用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);
Run Code Online (Sandbox Code Playgroud)
错误说:
类型'(number | undefined)[]'不能分配给'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[]);
Run Code Online (Sandbox Code Playgroud)
除了铸造之外,还有更好的方法来实现这一目标吗?
环境:TSC2.1启用了strictNullChecks.
小智 59
使用 TypeScript 的 User-Defined Type Guards 功能:
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]
Run Code Online (Sandbox Code Playgroud)
i is number
在回调函数中查看。这个技巧使我们能够投射 Array.filter 结果的类型。
Ema*_*röm 25
flatMap
以Typescript 理解的类型安全方式从数组中过滤值的最简单方法是使用map
返回一个空数组来删除您想要删除的任何内容。
例子:
const myArray = [1,2,3,4,"5",6,7, undefined,9, 0]
const filteredArray = arr.flatMap(val => typeof val === "number" ? val : [])
// filteredArray: [ 1, 2, 3, 4, 6, 7, 9, 0 ]
Run Code Online (Sandbox Code Playgroud)
flatMap
分两步进行。首先,它映射数组并执行您给它的任何函数。然后它会展平其中的所有数组。
映射数组并得到:
[ 1, 2, 3, 4, [], 6, 7, [], 9, 0 ]
展平数组中的所有数组:
[ 1, 2, 3, 4, 6, 7, 9, 0 ]
瞧!现在你有了一个类型化数组并且 Typescript 很高兴。
Kar*_*ski 15
解
创建一个类型保护:
function isDefined<T>(argument: T | undefined): argument is T {
return argument !== undefined
}
Run Code Online (Sandbox Code Playgroud)
使用它作为您的类型谓词:
const foo: number[] = [1, 2, undefined, 4].filter(isDefined)
Run Code Online (Sandbox Code Playgroud)
说明
Array.prototype.filter
有一些重载。其中之一了解返回值将取决于您的谓词函数。它使用类型保护:
filter<S extends T>(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
Run Code Online (Sandbox Code Playgroud)
使用适当的类型保护(而不是使用快捷方式并依靠隐式强制)可以帮助TypeScript选择此特定的重载。
该map(...)
函数签名是:
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
Run Code Online (Sandbox Code Playgroud)
在您的情况下,泛型类型U
将是:number | undefined
该filter(...)
签名是:
filter(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[];
Run Code Online (Sandbox Code Playgroud)
由于T
来自数组接口签名 ( Array<T>
),因此返回类型将是与value
参数类型相同的数组(泛型类型T
)。在你的情况下number | undefined
。
这就是为什么您的返回类型是number | undefined
.
基于此,您将需要使用强制转换表达式。如果您不想要这种行为,您可以删除该--strictNullChecks
标志。
内置filter
函数不可能,它被声明返回一个与它接收的类型完全相同的数组.
但是,可以定义自己的完全类型安全的过滤器函数,该函数接受数组和用户定义的类型保护函数,并返回不同类型的数组.
不确定有用,但这里是:
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;
}
Run Code Online (Sandbox Code Playgroud)
它可以像这样使用:
const arry = [1, 2, 3, 4, "5", 6];
function isNumber(e): e is number {
return typeof e === 'number';
}
const numArry: number[] = typeFilter(arry, isNumber);
Run Code Online (Sandbox Code Playgroud)
不幸的是,isNumber()
必须将其定义为单独的显式类型函数,因为编译器不够聪明,无法识别内联函数 e => typeof e === 'number'
也是类型保护.
归档时间: |
|
查看次数: |
1682 次 |
最近记录: |