Typescript构造函数参数工厂类型

Typescript构造函数参数工厂类型,typescript,generics,typescript-typings,Typescript,Generics,Typescript Typings,我有一些类,其构造函数需要形成标记并集的对象: interface Info { x: string; } interface AInfo extends Info { x: 'a'; } class A { constructor(info: AInfo) {} } interface BInfo extends Info { x: 'b'; } class B { constructor(info: BInfo) {} } type AllInfos = AIn

我有一些类,其构造函数需要形成标记并集的对象:

interface Info {
  x: string;
}

interface AInfo extends Info {
  x: 'a';
}

class A {
  constructor(info: AInfo) {}
}

interface BInfo extends Info {
  x: 'b';
}

class B {
  constructor(info: BInfo) {}
}

type AllInfos = AInfo|BInfo;
我省略了类内部和构造函数初始化。如何键入此工厂函数以关联基于传入信息创建的对象类型

const factory = (info: AllInfos) => {
  switch (info.x) {
    case 'a': return new A(info);
    case 'b': return new B(info);
    // ...
  }
};

const obj = factory(myInfo); // type of obj is A|B, I'd like it to vary by myInfo

最简单的方法是使用重载:

function factory(info: AInfo): A
function factory(info: BInfo): B
function factory(info: AllInfos) {
  switch (info.x) {
    case 'a': return new A(info);
    case 'b': return new B(info);
    // ...
  }
};

const objA = factory({ x: 'a' }); // A
const objB = factory({ x: 'b' }); // B

如果联盟中有很多选项,您可以创建一个分布式条件类型,为联盟中的每个成员创建一个签名,然后使用
UnionToIntersection
(请参阅):

类型UnionToIntersection=
(U扩展任何?(k:U)=>void:never)扩展((k:inferi)=>void)?I:从来没有
类型Factory=T扩展了new(p:inferp)=>inferr?(a:P)=>R:never
类型FactoryParameters=T扩展了新的(p:inferp)=>inferr?P:从来没有
类型所有类别=类型A |类型B
常量工厂=((信息:FactoryParameters

type UnionToIntersection<U> = 
  (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

type Factory<T> = T extends new (p: infer P) => infer R ? (a: P) => R : never
type FactoryParameters<T> = T extends new (p: infer P) => infer R  ? P : never
type AllClasses = typeof A | typeof B

const factory = ((info: FactoryParameters<AllClasses>) => {
  switch (info.x) {
    case 'a': return new A(info);
    case 'b': return new B(info);
  }
}) as UnionToIntersection<Factory<AllClasses>>;

const objA = factory({ x: 'a' }); // A
const objB = factory({ x: 'b' }); // B