28

考虑打开以下代码:strictNullChecks

var a: (number | null)[] = [0, 1, 2, 3, null, 4, 5, 6];
var b: { value: number; }[] = a.map(x => x != null && { value: x }).filter(Boolean);

由于以下原因无法编译:

Type '(false | { value: number; })[]' is not assignable to type '{ value: number; }[]'.
  Type 'false | { value: number; }' is not assignable to type '{ value: number; }'.
    Type 'false' is not assignable to type '{ value: number; }'.

但绝对清楚,那false将被 过滤掉.filter(Boolean)

同样的问题null

有没有办法(除了写作as number[])来标记该值不包含falseor null

4

2 回答 2

25

您可以使用这样的功能

function nonNullable<T>(value: T): value is NonNullable<T> {
  return value !== null && value !== undefined;
}

type Truthy<T> = T extends false | '' | 0 | null | undefined ? never : T; // from lodash

function truthy<T>(value: T): value is Truthy<T> {
    return !!value;
}

[1, 2, 0, null].filter(nonNullable) // number[]
[1, 2, 0, null].filter(truthy) // number[]

NonNullable - https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#predefined-conditional-types

于 2019-09-26T05:29:46.243 回答
22

如果您真的不想更改生成的 JavaScript,而是更愿意强制 TypeScript 编译器识别它Boolean作为false值防护,您可以这样做:

type ExcludesFalse = <T>(x: T | false) => x is T;     
var b: { value: number; }[] = a
  .map(x => x != null && { value: x })
  .filter(Boolean as any as ExcludesFalse);

这是有效的,因为您断言这Boolean是一个类型保护,并且因为如果回调是一个类型保护,Array.filter()它会被重载以返回一个缩小的数组。

上面的 ( Boolean as any as ExcludesFalse) 是我能想到的最干净的代码,它既可以工作又不会改变生成的 JavaScript。该常量Boolean被声明为全局BooleanConstructor接口的一个实例,您可以将一个ExcludesFalse类似类型的保护签名合并到BooleanConstructor中,但不能以一种允许您只说.filter(Boolean)并让它工作的方式。您可以使用类型保护变得更加花哨,并尝试表示防范所有虚假值(exceptNaN),但您的示例不需要它。

无论如何,希望有所帮助;祝你好运!

于 2017-12-04T15:03:53.097 回答