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和可能未定义的联合,因为这些是最常见的用例。


当前回答

你可以在.filter中使用类型谓词函数来避免选择退出严格的类型检查:

function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
    return value !== null && value !== undefined;
}

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

你也可以使用array.reduce<string[]>(…)。

2021年更新:更严格的谓词

虽然这种解决方案适用于大多数场景,但您可以在谓词中进行更严格的类型检查。如前所述,函数notEmpty实际上并不能保证它在编译时正确地识别值是null还是undefined。例如,尝试将其return语句缩短为return value !== null;,您将不会看到编译器错误,即使函数将在undefined上错误地返回true。

缓解这种情况的一种方法是首先使用控制流块约束类型,然后使用一个虚拟变量让编译器进行检查。在下面的例子中,编译器能够推断出value参数在赋值时不能为null或未定义。但是,如果您从if条件中删除|| value === undefined,则会看到编译器错误,通知您上面示例中的错误。

function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
  if (value === null || value === undefined) return false;
  const testDummy: TValue = value;
  return true;
}

提醒一句:在某些情况下,这种方法仍然会失败。一定要注意与逆变相关的问题。

其他回答

const filterdArray = array.filter(f => !!f) as string[];

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

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

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

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

使用减少

一些答案建议减少,下面是如何减少的:

const languages = ["fr", "en", undefined, null, "", "de"]

// the one I prefer:
languages.reduce<string[]>((previous, current) => current ? [...previous, current] : previous, [])

// or
languages.reduce((previous, current) => current ? [...previous, current] : previous, Array<string>())

// or
const reducer = (previous: string[], current: string | undefined | null) => current ? [...previous, current] : previous
languages.reduce(reducer, [])

结果:(“fr”、“en”、“de”)

这里是TS游乐场。

或者您可以尝试包:@p4ck93/ts-is

https://www.npmjs.com/package/@p4ck493/ts-is

示例使用CDN方法,但是包也支持typescript。

<script>var exports = {};</script> <script src="//unpkg.com/@p4ck493/ts-is@3.0.1/dist/index.js"></script> <script> const {is} = exports; console.log('is.string: ', is.string('')); // true console.log('is.string.empty: ', is.string.empty('')); // true console.log('is.string.not.empty: ', is.string.not.empty('')); // false const array = ["foo", "bar", null, "zoo", null]; const filterdArray = array.filter(is.string.not.empty); console.log('array:', array); console.log('filterdArray:', filterdArray); </script>

UPD

或打字稿:

Import {is} from '@p4ck493/ts-is'; Const array = ["foo", "bar", null, "zoo", null]; const filterdArray = array.filter(is.string.not.empty); /** 选择: array.filter (is.not.null); array.filter (is.not.empty); array.filter (is.string); * * /