定义 Typescript 类型谓词的最佳方法是什么,这些谓词在用于过滤数组时会产生最窄的类型?

问题描述 投票:0回答:1

我认为我已经找到了定义谓词的最佳方法:

declare function isNumber<T>(x: T): x is Extract<T, number>;
declare function isFunction<T>(x: T): x is Extract<T, Function>;
... and so on

这种方法在用于过滤数组时会产生很好的缩小类型,例如:

type Handler = () => void;

declare const a: (number|string)[];
declare const b: string[];
declare const c: (Handler|null)[];

const a1 = a.filter(isNumber);    // number[]  👍
const b1 = b.filter(isNumber);    // never[]   👍
const c1 = c.filter(isFunction);  // Handler[] 👍

不幸的是,

unknown
any
会导致令人惊讶的行为:

declare const d: any[];
declare const e: unknown[];

const d1 = d.filter(isNumber);  // any[]   😩 want number[]
const e1 = e.filter(isNumber);  // never[] 😩 want number[]

所以这毕竟不是最好的方法!然而,即使是 Typescript 手册中定义谓词的方法在用于过滤时也会表现得“奇怪”:

declare function isNumber2(x: any): x is number;
declare function isFunction2(x: any): x is Function;

const a2 = a.filter(isNumber2);    // number[]         👍
const b2 = b.filter(isNumber2);    // string[]         🤯 want never[]
const c2 = c.filter(isFunction2);  // (Handler|null)[] 🤯 want Handler[]
const d2 = d.filter(isNumber2);    // number[]         👍
const e2 = e.filter(isNumber2);    // number[]         👍

游乐场

我花了很长时间尝试各种方法,例如重载、通用参数约束等,以使其适用于所有上述情况,但一无所获。有没有一种方法可以定义谓词,在过滤时可以很好地缩小数组范围? (抱歉,我知道“很好”是主观的。通常它是最狭窄的预期类型。)或者我只需要选择一种可以容忍的方法?还在寻找指导,因为我目前正在学习 Typescript,所以我完全走在错误的道路上。

typescript types predicate
1个回答
0
投票

我认为你可以使用泛型和条件类型断言来实现你想要的。

declare function isNumber<T>(value: T): value is T extends number ? T : never;
declare function isFunction<T>(value: T): value is T extends Function ? T : never;

上面给出了我在每个示例中所期望的输出。

© www.soinside.com 2019 - 2024. All rights reserved.