Home > front end >  Map union type to another type
Map union type to another type

Time:07-06

I'm just curious know if this is possible in TypeScript. Imagine I've a list on entity identifiers defined as an union type:

type EntityID = 'authors' | 'books' | 'programs';

Then, imagine we have the following classes for each of these entities:

class Author { getBirthday() }
class Book {}
class Program {}

Is there a way to make this work at type level so that given a concrete EntityID TypeScript (and my IDE) know that the return type is a concrete entity class? Something like:

const book = genericGet('books', 10);
book.getBirthday() // This should fail at COMPILE TIME as it's an Author method

const author = genericGet('authors', 23);
author.getBirthday() // This is OK, as author is an Author

Thanks!

CodePudding user response:

You can create a mapping type from your enum to the types and then use a generic function (a factory method actually) to create the objects.

Something similar to this:

type EntityID = 'authors' | 'books' | 'programs';

type MapEntity = {
    'authors': Author,
    'books': Book,
    'programs': Program
}

class Author { 
    getBirthday = ()=>{

    } 
}
class Book {}
class Program {}

function genericGet<T extends keyof MapEntity>(type: T, ...args: any[]): MapEntity[typeof type] {
    switch (type) {
        case "authors":
            return new Author()
        case "books":
            return new Book() as any
        case "programs":
            return new Program() as any
        default:
            throw Error()
    }
}

const book = genericGet('books', 10);
book.getBirthday() // This should fail at COMPILE TIME as it's an Author method

const author = genericGet('authors', 23);
author.getBirthday() // This is OK, as author is an Author

A couple of notes:

  • You don't need to pass the generic type when using the factory method, as TS will infer it
  • You need to specify a default clause for the switch even though there are no options there. This is so TS flow analysis is satisfied.
  • The type for the variables that call genericGet is properly infered

Here is playground to showcase this:

  • Related