Typescript 扩展了狭窄的通用类型

Typescript Expands Narrowed Generic Type

我有这个代码:

type Constructable = {new(...args: any[]): any, prototype: any}; // Represents a class (that can be called with new)

type WithOnlyType<O, T> = {[P in keyof O as O[P] extends T? P: never]: O[P]}; // 

// Override a constructor with name C in a scope S
function extendConstructor<
    S,
    T extends WithOnlyType<S, Constructable>,
    C extends keyof T>
    (
        className: C, constructor: (...args: ConstructorParameters<T[C]>) => any, scope: S) {

...}

但是,ConstructorParameters<T[C]> 是错误的,因为 Type 'T[C]' does not satisfy the constraint 'abstract new (...args: any) => any'. 这很奇怪,因为 T 只包含满足该要求的值(Constructable),而 C 是 keyof T。但是,在错误的更下方(底部),我发现:

Type 'S[string]' is not assignable to type 'abstract new (...args: any) => any'

这是真的,S 可以有比 类 更多的值,但是,T 比 S 窄得多,C 比字符串窄得多。如何阻止 tsc 扩展这些类型?

Typescript 不会遵循映射的条件类型将导致 T[C] 是可构造的。

您可以重新构造您的类型参数并使其工作:

function extendConstructor<
    S extends Record<C, Constructable>,
    C extends keyof WithOnlyType<S, Constructable>>
    (className: C, constructor: (...args: ConstructorParameters<S[C]>) => any, scope: S) {

}

Playground Link

注意:我建议将 scope 放在第一位,以便更好地完成密钥上的代码。

这是 TypeScript 的设计限制。有关类似问题的描述,请参阅 microsoft/TypeScript#30728。当 TC 是都是未指定的泛型类型参数。您专门编写了 WithOnlyType 来保证这种约束,但是 WithOnlyType<S, Constructable>[keyof WithOnlyType<S, Constructable>] 或多或少对编译器来说是不透明的。

如果您想解决这个问题,可以使用 the Extract<T, U> utility type。当你有一个 知道的类型 T 可以分配给类型 U 但编译器不知道这一点时,你可以写成 Extract<T, U> T 个。编译器看到 Extract<T, U> 可分配给 U,并且您知道 Extract<T, U> 最终将解析为任何 T 是什么(因为 Extract<T, U> 计算为任何联合T 的成员可分配给 U).

所以如果你改变

ConstructorParameters<T[C]>

ConstructorParameters<Extract<T[C], Constructable>>

错误将消失。

Playground link to code