tdranv
tdranv

Reputation: 1330

Typesafe factory function

I have two functions:

const createPerson = (age: number, name: string) => {};

const createCar = (model: string) => {}

I wish to create a generic factory function that accepts an argument and based on that argument returns one of the two functions. Something like:

enum Argument {
    Person = 'person',
    Car = 'car'
}

type Pairs = {
    [Argument.Person]: typeof createPerson;
    [Argument.Car]: typeof createCar;
}

const factory = <K extends keyof Pairs>(type: K): Pairs[K] => {
    if (type === Argument.Person) return createPerson;
    if (type === Argument.Car) return createCar
};

It's all fine and dandy but the Pairs[K] seems to be causing problems as I get an error:

Type '(age: number, name: string) => void' is not assignable to type 'Pairs[K]'.
  Type '(age: number, name: string) => void' is not assignable to type '((age: number, name: string) => void) & ((model: string) => void)'.
    Type '(age: number, name: string) => void' is not assignable to type '(model: string) => void'.

How can I make it not merge the two types (as it's evident from the error message, &)?

Upvotes: 0

Views: 97

Answers (1)

Oblosys
Oblosys

Reputation: 15106

In this case you can avoid the problems with the generic return type by indexing an object of pairs:

const pairs = {
    [Argument.Person]: createPerson,
    [Argument.Car]: createCar,
}

type Pairs = typeof pairs

const factory = <K extends keyof Pairs>(type: K): Pairs[K] => pairs[type]

TypeScript playground

Upvotes: 1

Related Questions