【问题标题】:How to avoid casting instance class type?如何避免强制转换实例类类型?
【发布时间】:2020-12-29 11:10:43
【问题描述】:

我想创建一个类型正确的函数,它接收带有服务名称的参数并返回该服务的实例。如果不强制转换实例,我将无法获得结果。

用一个简化的例子更好地解释:

class ECR {
    public image(): void {}
}

class ECS {
    public cluster(): void {}
}

const aws = {
    ECR,
    ECS
};

type Aws = {
    ECR: ECR
    ECS: ECS
}

function createService<T extends 'ECR' | 'ECS'>( serviceName: T, aws: typeof AWS ): Aws[T] {
    const Constr = aws[ serviceName ];

    const f: Aws[T] = new Constr(); // here I receive the error if do not cast it 'as Aws[T]'

    return f;
}

错误:

Type 'ECR | ECS' is not assignable to type 'Aws[T]'.
  Type 'ECR' is not assignable to type 'Aws[T]'.
    Type 'ECR' is not assignable to type 'ECR & ECS'.
      Property 'cluster' is missing in type 'ECR' but required in type 'ECS'.

知道如何在不需要强制转换的情况下正确键入此函数吗?

【问题讨论】:

    标签: typescript types casting typescript-generics


    【解决方案1】:

    这行得通:

    type MapToConstructor<T> = { [K in keyof T]: new () => T[K] };
    
    function createService<T extends 'ECR' | 'ECS', U extends Aws = Aws>(
      serviceName: T,
      aws: MapToConstructor<U>
    ): U[T] {
        const Constr = aws[ serviceName ];
        const f = new Constr();
        return f;
    }
    

    (Playground link)

    我不完全解释为什么这会起作用,但我认为这与 TS 由于泛型而推迟对 Constr 类型的评估有关。在上面的工作示例中,将鼠标悬停在new Constr() 中的Constr 上表明它的类型是new () =&gt; U[T],但在下面的代码中执行相同操作会显示new () =&gt; ECR | ECS

    function notWorking<T extends 'ECR' | 'ECS'>(
      serviceName: T,
      aws: MapToConstructor<Aws>
    ): Aws[T] {
        const Constr = aws[ serviceName ];
        const f = new Constr();
        return f;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-30
      • 2020-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-04
      • 2014-11-26
      相关资源
      最近更新 更多