首页 > 解决方案 > TypeScript 3.5 和 3.6 之间的泛型参数推断不匹配

问题描述

我试图理解以下代码的类型检查:

const marker = Symbol();

type ConstItem = string | number | null;
type Item = ConstItem | { [index: string]: string };
type WrapOrConst<T extends Item> = Wrap<T> | (T extends ConstItem ? T : never);
type Wrap<T extends Item> = {
    __marker: typeof marker,
    __phantom: T;
}

declare function wrapped<T extends Item>(item: T): Wrap<T>;
declare function str(): string;

type UnionInner<T extends Array<WrapOrConst<Item>>> = T extends Array<WrapOrConst<infer U>> ? U : never;
declare function Union<T extends WrapOrConst<Item>[]>(...inner: T): Wrap<UnionInner<T>>;

const test = Union(wrapped(str()), null);
const test2: string | null = test.__phantom;

操场

这在 TypeScript 3.6 中运行良好,但在 TypeScript 3.5 中失败,因为test推断为 beWrap<Item>和 not Wrap<string | null>。我无法在发行说明中找到任何内容;它只是一个错误吗?我可以在早期版本中以某种方式解决这个问题(理想情况下,直到 TypeScript 3.1)?

标签: typescripttypescript-generics

解决方案


是的,它被认为是一个错误 ( microsoft/TypeScript#32434 ),其中涉及某些联合的泛型类型参数推断会产生不良结果。如您所见,TypeScript 3.6已修复 (microsoft/TypeScript#32460)

要使您的代码在以前的版本中工作,您可能必须重构以在推理站点中包含更少的显式联合,如下所示:

type Unwrap<U extends Item | Wrap<Item>> = U extends Wrap<infer I> ? I : U
declare function Union<T extends WrapOrConst<Item>[]>(...inner: T): Wrap<Unwrap<T[number]>>;

这似乎表现得像你想要的那样:

const test = Union(wrapped(str()), null).__phantom; // string | null

但是,我当然不知道您拥有的全部用例,因此可能存在一些边缘情况,其中所需的行为与上述行为不同。但这应该有希望让您了解如何进行。

好的,希望有帮助;祝你好运!

链接到代码


推荐阅读