Typescript和过滤器Boolean

54

考虑以下使用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[] 的方式,是否有其他办法标记值不包含 falsenull

4个回答

70

您可以使用如下函数

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


3
我认为这应该是被接受的答案。 - vcarel

29

如果你真的不想改变生成的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)并让它工作。你可以使用更复杂的类型保护,尝试表示防止所有假值(除了 NaN),但在你的例子中不需要这样做。
总之,希望这有所帮助,祝你好运!

3
甚至你可以这样做:const ExcludesFalse = Boolean as any as <T>(x: T | false) => x is T; array.filter(ExcludesFalse);(翻译:该代码段的含义为,定义了一个名为"ExcludesFalse"的常量,它强制将类型为“T | false”的参数转化为类型为“T”的返回值,并将其用作泛型函数的断言。最后,使用该函数过滤掉数组中值为false的元素。) - Chris'
10
.filter(<T>(n?: T): n is T => Boolean(n)) 在至少 3.1.6 版本上可用。该方法会对元素进行过滤,使得只有符合指定条件的元素能够通过过滤器,并返回一个新的数组。在这个方法中,<T> 表示泛型,n?: T 表示可选参数,n is T 表示类型谓词,Boolean(n) 则是将参数转换为布尔值并返回它的结果。 - Filipe Borges

4
您可以像这样排除任何非空值。
type ValidValue<T> = Exclude<T, null | undefined | 0 | '' | false>;
const BooleanFilter = <T>(x: T): x is ValidValue<T> => Boolean(x);
var a: (number | null)[] = [0, 1, 2, 3, null, 4, 5, 6, undefined];
const values = Object.values(a).filter(BooleanFilter);
console.log(values)  // [ 1, 2, 3, 4, 5, 6 ]

2
export function isTruthy<T>(value?: T | undefined | null | false): value is T {
  return !!value
}

然后执行。
const arrayWithNoFalsyValues = arrayWithFalsyValues.filter(isTruthy)

arrayWithNoFalsyValues 类型将是 T[] 而不是 (T | null | ...)[]

可以随意添加更多 falsy 值/类型到 isTruthy(value) 中的 value 类型中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接