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 validData = array.filter(Boolean)

其他回答

如果您可以接受另一个.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 filteredArray: string[] = array.filter((s): s is string => Boolean(s));

打印稿操场

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

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

TypeScript有一些实用工具来推断数组的类型并排除null值:

const arrayWithNulls = ["foo", "bar", null, "zoo", null]

type ArrayWithoutNulls = NonNullable<typeof arrayWithNulls[number]>[]

const arrayWithoutNulls = arrayWithNulls.filter(x => x != null) as ArrayWithoutNulls

比在新数组上手动转换为string[]更长,但更安全。

循序渐进:

从原始数组中获取类型:

typeof arrayWithNulls[number] // => string | null

排除空值:

NonNullable<typeof arrayWithNulls[number]> // => string

让它成为一个数组:

NonNullable<typeof arrayWithNulls[number]>[] // => string[]

链接:

NonNullable(官方文档) typeof array[number](博客文章,我在官方文档中找不到任何关于它的东西)

如果您已经使用了Lodash,您可以使用compact。 或者,如果你喜欢Ramda, Ramda的附属品也有紧凑的功能。

两者都有类型,所以您的tsc会很高兴,并得到正确的类型。

从Lodash d.ts文件:

/**
 * Creates an array with all falsey values removed. The values false, null, 0, "", undefined, and NaN are
 * falsey.
 *
 * @param array The array to compact.
 * @return Returns the new array of filtered values.
 */
compact<T>(array: List<T | null | undefined | false | "" | 0> | null | undefined): T[];

我认为这将是一个简单的方法,有更清晰的代码

const array: (string | null)[] = ['foo', 'bar', null, 'zoo', null];
const filteredArray: string[] = array.filter(a => !!a);