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 nonNull = array.filter((e): e is Exclude<typeof e, null> => e !== null)

这样你:

得到一行代码,没有附加函数 不需要知道数组元素的类型,所以你可以到处复制!

其他回答

或者您可以尝试包:@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); * * /

为了避免每个人都不得不一遍又一遍地编写相同类型的保护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捆绑这个功能时,我将删除这个包。但是,现在,享受吧。

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

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

结合上面我最喜欢的答案之一,与一些通用技巧和对Array接口的扩展,我能够做出一个全局定义,添加到您的模块后,允许任何数组被“压扁”,删除所有空值替换(任何|undefined|null)[]与任何[]。

mixedarray . squash()适合链接和映射。

只需在模块的某个地方添加这段代码(可以随意省略eslint的东西,但我的set在这里的一些事情让我感到困扰):

/* eslint-disable no-unused-vars */
/* eslint-disable no-extend-native */
declare global {
  interface Array<T> {
    squish<NonNull, Nullable extends (NonNull | undefined | null)>(): NonNull[];
  }
}

if (!Array.prototype.squish) {
  Array.prototype.squish = function squish<NonNull, T extends(NonNull|undefined|null)>
  (this: T[]): NonNull[] {
    return this.flatMap((e) => (e ? [e] : [])) as NonNull[]
  }
}

使用减少

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

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游乐场。