TypeScript,——strictNullChecks模式。

假设我有一个可空字符串数组(string | null)[]。什么是单表达式的方式,以这样的方式删除所有的空值,结果有类型字符串[]?

const array: (string | null)[] = ["foo", "bar", null, "zoo", null];
const filterdArray: string[] = ???;

数组中。过滤器在这里不起作用:

// Type '(string | null)[]' is not assignable to type 'string[]'
array.filter(x => x != null);

数组推导式可以工作,但TypeScript不支持。

实际上,这个问题可以推广为通过从联合中删除具有特定类型的项来过滤任何联合类型的数组的问题。但是让我们关注带有null和可能未定义的联合,因为这些是最常见的用例。


当前回答

一个衬套:

const filteredArray: string[] = array.filter((s): s is string => Boolean(s));

打印稿操场

诀窍是传递一个类型谓词(:s是字符串语法)。

这个答案显示了数组。过滤器要求用户提供类型谓词。

其他回答

还有一个很好的措施,因为人们经常忘记flatMap可以一次性处理过滤器和映射(这也不需要任何类型转换字符串[]):

// (string | null)[]
const arr = ["a", null, "b", "c"];
// string[]
const stringsOnly = arr.flatMap(f => f ? [f] : []);

为了避免每个人都不得不一遍又一遍地编写相同类型的保护helper函数,我将称为isPresent, isDefined和isfill的函数绑定到一个helper库:https://www.npmjs.com/package/ts-is-present

当前类型定义为:

export declare function isPresent<T>(t: T | undefined | null): t is T;
export declare function isDefined<T>(t: T | undefined): t is T;
export declare function isFilled<T>(t: T | null): t is T;

你可以这样使用:

import { isDefined } from 'ts-is-present';

type TestData = {
  data: string;
};

const results: Array<TestData | undefined> = [
  { data: 'hello' },
  undefined,
  { data: 'world' }
];

const definedResults: Array<TestData> = results.filter(isDefined);

console.log(definedResults);

当Typescript捆绑这个功能时,我将删除这个包。但是,现在,享受吧。

如果您可以接受另一个.map()的开销,一个优雅的解决方案是使用非空断言操作符。

const array = ["foo", "bar", null, "zoo", null];
const filterdArray: string[] = array.filter(s => s != null).map(s => s!);

如果你想保留未定义,你可以在变量上使用typeof,并使用实用程序类型Exclude来从类型中删除空值。

const array = ["foo", "bar", null, "zoo", null];
const filterdArray: string[] = array
  .filter(s => s !== null)
  .map(s => s as Exclude<typeof s, null>);
const filterdArray = array.filter(f => !!f) as string[];

如果你使用过滤器检查null和其他条件,这可以简单地使用,希望这有助于寻找对象数组的解决方案的人

array.filter(x => x != null);
array.filter(x => (x != null) && (x.name == 'Tom'));