【问题标题】:Using typescript Exclude with generic type使用带有泛型类型的打字稿排除
【发布时间】:2020-11-20 06:16:11
【问题描述】:

我基于 TypeScript 的 Nodejs 项目中的依赖项的例行更新导致我在用于管理 mongoose 模型的通用类中收到 TypeScript 编译错误。我已将问题缩小到似乎是 TypeScript 处理泛型类型的问题。

我构建了以下最小示例:

interface I {
    p: string;
}

class Foo<T extends I> {
    exclude: Exclude<'p', 'q'> = 'p'; // OK
    excludeI: Exclude<keyof I, 'q'> = 'p'; // OK
    excludeT: Exclude<keyof T, 'q'> = 'p'; // TS2322: Type '"p"' is not assignable to type 'Exclude<keyof T, "q">'.
}

请注意excludeI(编译良好)和excludeT(编译失败并出现给定错误)类型之间的唯一区别是后者使用泛型类型T而不是接口类型I.

由于T 被指定为扩展I,我希望这两行得到相同的处理。事实上,keyof 运算符似乎可以互换使用它们:

class Foo<T extends I> {
    keyof: 'p' = 'p'; // OK
    keyofI: keyof I = 'p'; // OK
    keyofT: keyof T = 'p'; // OK
}

我曾使用this example on the TypeScript Playground 尝试过不同的 TS 版本,它似乎不是版本依赖的行为。

谁能在这里解释一下Exclude<> 发生了什么?

【问题讨论】:

  • github.com/microsoft/TypeScript/issues/33484 这似乎实际上是打字稿的问题,但不知道如何解决它
  • 感谢@AlexChashin 的链接,如果不是相同的问题,它肯定似乎是密切相关的。仍然不确定keyof 如何按预期工作,但随后Exclude 不会。
  • 请注意,在您的操场示例中,您的 extendsXX 类型与使用 Exclude 的类型不同;后者是 distributive condtional type 但你的 extendsXX 类型不是。

标签: typescript typescript-generics


【解决方案1】:

这是 TypeScript 编译器的限制。编译器通常不可能验证依赖于未指定的 generic 类型参数的 conditional type 的值的可分配性。在这种情况下,条件类型的评估会延迟直到指定类型参数,在此之前,类型对编译器来说或多或少是不透明的。

Exclude 实用程序类型是 defined 作为条件类型,如下所示:

type Exclude<T, U> = T extends U ? never : T;

由于T 是泛型类型参数,那么Exclude&lt;keyof T, 'p'&gt; 是依赖于泛型类型参数的条件类型。在 Foo 类定义中,T 未指定,因此您可能会从那里看到编译器有些不智能的行为。


这是几个 GitHub 问题的主题,例如 microsoft/TypeScript#33484 关于 Omit 无法识别这种可分配性(Omit 目前是用 Exclude 实现的),或者 microsoft/TypeScript#28884 关于如何看不到 Pick&lt;T, K&gt; &amp; Omit&lt;T, K&gt;可分配给Tmicrosoft/TypeScript#36737,说明您如何无法在返回通用条件类型的函数中轻松返回值。


那么,你该如何继续呢?这里的正确答案可能只是接受你比编译器更聪明,并使用type assertion 告诉编译器你确信你正在做的事情是安全的,即使编译器不是:

excludeT = "p" as Exclude<keyof T, "p">; // okay

或者,如果您可以避免使用特定类型而不是泛型类型,编译器可以更轻松地对此进行推理,正如您所见:

excludeI: Exclude<keyof I, 'q'> = 'p'; // OK

Playground link to code

【讨论】:

  • 我确实对 Mongoose 遇到的实际问题使用了类型断言,尽管我花了相当长的时间来解开该库内部使用的各种嵌套泛型以确定我应该使用哪种类型甚至假装在使用!我仍然不能 100% 确定为什么 keyof 对于编译器来说应该比 Exclude 更“容易”,但是你已经提供了很多有用的信息——谢谢!
猜你喜欢
  • 2021-11-09
  • 2021-02-25
  • 2021-11-26
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 2020-05-09
相关资源
最近更新 更多