【问题标题】:TypeScript conditional types with classes that are structurally equivalentTypeScript 条件类型的类在结构上是等效的
【发布时间】:2020-10-08 03:47:09
【问题描述】:

我有类似以下的内容:

declare class Base {
  constructor(a: string)
}

declare class A extends Base {
  constructor(a: number)
}

declare class B extends Base {
  constructor(a: object)
}

declare class C extends Base {
  constructor(a: boolean)
}

type ResponseMapper<T extends Base> = T extends A 
  ? number 
  : T extends B 
  ? object 
  : T extends C 
  ? boolean 
  : never;

declare function getValue<T extends Base>(input: T): ResponseMapper<T>

let x: number = getValue(new A(1))
let y: object = getValue(new B({}))
let z: boolean = getValue(new C(true))

TS Playground

这并不完全有效,因为 A、B 和 C 在结构上都是等效的。所以在ResponseMapper 中,如果我传入BC 的实例,它仍然会计算为number。所以yz 的变量声明最终会出现类型错误。

我想出一个解决方法是为每个类添加一个假属性,使类型在结构上不再是等效的。所以这行得通:

declare class Base {
  constructor(a: string)
}

declare class A extends Base {
  _name?: "A"
  constructor(a: number)
}

declare class B extends Base {
  _name?: "B"
  constructor(a: object)
}

declare class C extends Base {
  _name?: "C"
  constructor(a: boolean)
}

type ResponseMapper<T extends Base> = T extends A 
  ? number 
  : T extends B 
  ? object 
  : T extends C 
  ? boolean 
  : never;

declare function getValue<T extends Base>(input: T): ResponseMapper<T>

let x: number = getValue(new A(1))
let y: object = getValue(new B({}))
let z: boolean = getValue(new C(true))

TS Playground

有没有更好的方法来让它工作而不需要添加假字段?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    在这里,尝试使用这种类型:

    type ResponseMapper<T, U> = T extends new (a: infer R) => U ? R : never;
    
    declare function getValue<T extends new (a: V) => U, U, V = ResponseMapper<T, U>>(input: U): V;
    

    TS Playground

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-13
      • 1970-01-01
      • 2020-09-22
      • 2021-01-31
      • 2020-03-29
      • 2012-01-05
      • 2018-10-20
      • 1970-01-01
      相关资源
      最近更新 更多