缩小工厂退货类型而不通过课堂的最佳方法

时间:2018-12-16 03:58:27

标签: typescript generics factory union-types

我正在尝试找到一种最佳方法来缩小工厂的退货类型,而无需传入类本身。以下是使用条件类型的示例,这是到目前为止我发现的最佳方法。有没有一种更清洁的方法来缩小返回类型?

设置

class Lion {
  run() {
    // Do something
  }
}

class Fish {
  swim() {
    // Do something
  }
}

class Snake {
  slither() {
    // Do something
  }
}

enum AnimalType {
  LION = 'lion',
  FISH = 'fish',
  SNAKE = 'snake',
}

此示例返回我不想要的联合类型

class AnimalFactory {
  public static create(type: AnimalType) {
    switch (type) {
      case AnimalType.LION:
        return new Lion();
      case AnimalType.FISH:
        return new Fish();
      case AnimalType.SNAKE:
        return new Snake();
      default:
        throw new Error('Invalid Type');
    }
  }
}

const fish = AnimalFactory.create(AnimalType.FISH); // Type: Lion | Fish | Snake :(

此示例返回正确的类型,但似乎有很多开销

type Animal<T> = T extends AnimalType.LION
  ? Lion
  : T extends AnimalType.FISH
  ? Fish
  : T extends AnimalType.SNAKE
  ? Snake
  : unknown;

class AnimalFactory {
  public static create<T extends AnimalType>(type: T): Animal<T> {
    switch (type) {
      case AnimalType.LION:
        return new Lion() as Animal<T>;
      case AnimalType.FISH:
        return new Fish() as Animal<T>;
      case AnimalType.SNAKE:
        return new Snake() as Animal<T>;
      default:
        throw new Error('Invalid Type');
    }
  }
}

const fish = AnimalFactory.create(AnimalType.FISH); // Type: Fish :)

是否有一种更清洁的方法来仅使用AnimalType参数来缩小工厂退货类型?

1 个答案:

答案 0 :(得分:3)

您需要一个类型,该类型描述为哪个枚举值返回哪种类类型:

interface AnimalFactoryReturnType {
  [AnimalType.LION]: Lion;
  [AnimalType.FISH]: Fish;
  [AnimalType.SNAKE]: Snake;
}

然后您可以使用keyof将其选中:

class AnimalFactory {
  public static create<T extends keyof AnimalFactoryReturnType>(type: T): AnimalFactoryReturnType[T] {
    switch (type) {
      case AnimalType.LION:
        return new Lion();
      case AnimalType.FISH:
        return new Fish();
      case AnimalType.SNAKE:
        return new Snake();
      default:
        throw new Error('Invalid Type');
    }
  }
}

const fish = AnimalFactory.create(AnimalType.FISH); // Type: Fish :)