Skapa en TypeScript-generisk typ som mappar godtyckligt namngivna typer till andra typer
Jag har lite kod som kopplar 'till -> från'-typer på det här sättet:
/**
* From types:
*/
type Kitten = {
kind: 'kitten';
};
type Puppy = {
kind: 'puppy';
};
/**
* To types:
*/
type Cat = {
kind: 'cat';
};
type Dog = {
kind: 'dog';
};
/**
* Existing generic "condtional type" that converts any "FROM" -> "TO" using nested ternaries (slow when big):
*/
type ConvertType<T> =
T extends Kitten ? Cat
: T extends Puppy ? Dog
: never;
Men i verkligheten finns det över 100 paravbildningar, och därför nästlade ternära villkor, vilket verkligen saktar ner TypeScript.
Finns det något bättre sätt att göra detta utan att använda en långsam "villkorlig typ"?
Jag vet att det också skulle kunna göras med en dummyfunktion med överlagringar som detta...
function convert_function(input: Kitten): Cat;
function convert_function(input: Puppy): Dog;
function convert_function(input: unknown) {
return input;
}
...men jag undrar om det kan göras enbart med typningssystemet, eftersom jag redan använder ConvertType<T>, men utan prestandaproblemen.
Svar #1
Du borde kunna skapa en union som representerar de parningar du bryr dig om, som
type TypeMap = [Kitten, Cat] | [Puppy, Dog]
Det använder tupler för att para ihop saker, men du kan använda vilken typ du vill, till exempel {i: Kitten, o: Cat} | {i: Puppy, o: Dog}, så länge det är konsekvent.
Och sedan kan en enda distributiv konditionell typ filtrera det på lämpligt sätt:
type ConvertType<T> = Extract<TypeMap, [T, any]>[1]
Detta använder Extract-verktygstypen (implementerad som en distribuerande villkorlig typ) för att filtrera TypeMap till bara den post vars första element är T, och sedan indexerar det in i den posten för att få det andra elementet (med index 1).
Låt oss prova det:
type X = ConvertType<Kitten>
// ^? type X = Cat
type Y = ConvertType<Puppy>
// ^? type Y = Dog
Ser bra ut.
Playground-länk till kod
