即使等效条件类型有效,类型保护也无法正常工作
Type guard not working properly even though equivalent conditional type works
考虑以下条件类型的声明和使用:
type IsIterable<T> = T extends Iterable<infer X> ? Iterable<X> : never
export function isIterableAny(val: any): val is IsIterable<typeof val> {
return hasValue(val) && typeof (val as any)[Symbol.iterator] === "function"
}
export function isIterableUnknown(val: unknown): val is IsIterable<typeof val> {
return hasValue(val) && typeof (val as any)[Symbol.iterator] === "function"
}
const num = 1 // 1
const arr = [1, 2, 3] // number[]
type TestNumber = IsIterable<typeof num> // never
type TestArray = IsIterable<typeof arr> // Iterable<number>
if (isIterableAny(num)) { num /* 1 & Iterable<unknown> */ }
if (isIterableUnknown(num)) { num /* never */ }
if (isIterableAny(arr)) { arr /* number[] */ }
if (isIterableUnknown(arr)) { arr /* never */ }
为什么 isIterable
类型保护的结果与测试类型的结果不对应,即使它们都使用相同的条件类型 IsIterable
?
我注意到类型保护的两个版本以 different/complementary 方式工作和失败,但当然我需要一个适用于所有输入的类型保护
type IsIterable<T> = T extends Iterable<infer X> ? Iterable<X> : never;
通过使用它,您将丢弃与 T 相关的所有类型信息,而不是它的可迭代属性。相反,您只需要从联合 T
中排除所有不扩展 Iterable
类型的成员:
export function isIterable<T>(value: T): value is T extends Iterable<any> ? T : never {
try { return typeof (value as any)[Symbol.iterator] === 'function'; }
catch { return false; }
}
declare const num: 1;
isIterable(num) && num; // never
declare const arr: number[];
isIterable(arr) && arr; // number[]
declare const union: null | string[] | Generator<bigint> | Iterator<number> | Record<'a' | 'b', boolean>;
isIterable(union) && union; // string[] | Generator<bigint>
考虑以下条件类型的声明和使用:
type IsIterable<T> = T extends Iterable<infer X> ? Iterable<X> : never
export function isIterableAny(val: any): val is IsIterable<typeof val> {
return hasValue(val) && typeof (val as any)[Symbol.iterator] === "function"
}
export function isIterableUnknown(val: unknown): val is IsIterable<typeof val> {
return hasValue(val) && typeof (val as any)[Symbol.iterator] === "function"
}
const num = 1 // 1
const arr = [1, 2, 3] // number[]
type TestNumber = IsIterable<typeof num> // never
type TestArray = IsIterable<typeof arr> // Iterable<number>
if (isIterableAny(num)) { num /* 1 & Iterable<unknown> */ }
if (isIterableUnknown(num)) { num /* never */ }
if (isIterableAny(arr)) { arr /* number[] */ }
if (isIterableUnknown(arr)) { arr /* never */ }
为什么 isIterable
类型保护的结果与测试类型的结果不对应,即使它们都使用相同的条件类型 IsIterable
?
我注意到类型保护的两个版本以 different/complementary 方式工作和失败,但当然我需要一个适用于所有输入的类型保护
type IsIterable<T> = T extends Iterable<infer X> ? Iterable<X> : never;
通过使用它,您将丢弃与 T 相关的所有类型信息,而不是它的可迭代属性。相反,您只需要从联合 T
中排除所有不扩展 Iterable
类型的成员:
export function isIterable<T>(value: T): value is T extends Iterable<any> ? T : never {
try { return typeof (value as any)[Symbol.iterator] === 'function'; }
catch { return false; }
}
declare const num: 1;
isIterable(num) && num; // never
declare const arr: number[];
isIterable(arr) && arr; // number[]
declare const union: null | string[] | Generator<bigint> | Iterator<number> | Record<'a' | 'b', boolean>;
isIterable(union) && union; // string[] | Generator<bigint>