繁体   English   中英

使用带有泛型类型的打字稿排除

[英]Using typescript Exclude with generic type

我的基于 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
}

在 TypeScript Playground 上使用了这个例子来试验不同的 TS 版本,它似乎不是依赖于版本的行为。

任何人都可以阐明Exclude<> 的情况吗?

这是 TypeScript 编译器的限制。 对于依赖于未指定泛型类型参数的条件类型,编译器通常无法验证值的可赋值性。 在这种情况下,条件类型的评估会推迟到指定类型参数之前,并且在此之前,类型对编译器或多或少是不透明的。

Exclude实用程序类型定义为条件类型,如下所示:

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

由于T是泛型类型参数,因此Exclude<keyof T, 'p'>是依赖于泛型类型参数的条件类型。 Foo类定义内部, T是未指定的,因此您会在那里看到编译器的一些不智能的行为。


这是几个 GitHub 问题的主题,例如microsoft/TypeScript#33484关于Omit无法识别这种可分配性( Omit当前使用Exclude实现),或microsoft/TypeScript#28884关于Pick<T, K> & Omit<T, K>不被视为可分配给Tmicrosoft/TypeScript#36737关于如何在返回通用条件类型的函数中无法轻松返回值。


那么,你怎么能继续呢? 这里的正确答案可能只是接受你比编译器更聪明,并使用类型断言告诉编译器你确定你正在做的事情是安全的,即使编译器不是:

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

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

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

Playground 链接到代码

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM