【问题标题】:Typescript using mapped types with arrays使用带有数组的映射类型的打字稿
【发布时间】:2021-04-20 22:12:50
【问题描述】:

我正在尝试将映射类型与打字稿一起使用,这应该是可能的,但遇到了一些问题。

假设我有 3 个班级:

class A {
    public foo1 = 1;
}
class B {
    public foo2 = 1;
}
class C {
    public foo3 = 1;
}

const base = [A, B, C] as const;

基本上,我想要的是将base 传递给某个函数,并返回一个包含 3 个匹配实例的数组。

type CTOR = new(...args: any[]) => any

function instantiate1<T extends ReadonlyArray<CTOR>>(arr: T): {[K in keyof T]: T[K]} {
    const items = arr.map(ctor => new ctor());
    return items as any; //Don't mind about breaking type safety inside the function
}

现在返回:

const result1 = instantiate2(base) //type is [typeof A, typeof B, typeof C]

这是有道理的,因为我还没有真正“映射”类型,只是确保语法有效。

但是,如果我尝试实际映射类型:

function instantiate2<T extends ReadonlyArray<CTOR>>(arr: T): {[K in keyof T]: InstanceType<T[K]>} {
    const items = arr.map(ctor => new ctor());
    return items as any; //Don't mind about breaking type safety inside the function
}

我收到T[K] 不满足实例类型约束的错误。

任何人都可以作为解决方法的想法?

full playground link

【问题讨论】:

    标签: typescript


    【解决方案1】:

    根据microsoft/Typescript#27995,这是 TypeScript 中的一个已知错误。这是一个相当老的问题,并且在“积压”中,所以我不希望它很快得到修复。


    解决方法:

    T[K] 显式约束为所需的构造函数类型。我通常用Extract&lt;T, U&gt; utility type 这样做:

    declare function instantiate<T extends ReadonlyArray<Ctor>>(arr: T): {
        [K in keyof T]: InstanceType<Extract<T[K], Ctor>>
    };
    
    const result = instantiate(base);
    // const result: readonly [A, B, C]
    

    或者,您可以将InstanceType&lt;T&gt; utility type 替换为您自己的版本,而不关心T 是否是构造函数。 existing type definition 是:

    type InstanceType<T extends new (...args: any) => any> = 
       T extends new (...args: any) => infer R ? R : any;
    

    所以你可以把它放宽到:

    type MyInstanceType<T> = // no constraint on T
        T extends new (...args: any) => infer R ? R : any;
    

    然后您的原始版本按预期工作:

    declare function instantiate<T extends ReadonlyArray<Ctor>>(arr: T): {
        [K in keyof T]: MyInstanceType<T[K]>
    };
    
    const result = instantiate(base);
    // const result: readonly [A, B, C]
    

    Playground link to code

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-19
      • 1970-01-01
      • 2018-06-16
      • 2019-10-12
      • 2022-12-07
      • 1970-01-01
      • 1970-01-01
      • 2022-01-06
      相关资源
      最近更新 更多