Home > database >  Using a transformer type to map the value of each key into another type
Using a transformer type to map the value of each key into another type

Time:10-03

With my first type as

type First = {
  a: string,
  b: number
}

Open to changes on how the Dictionary is implemented. A dictionary type could be as follows

type Dictionary = {
  string: { "stringValue": string },
  number: { "numberValue": number }
}

How do I make it so that I can create some Transform<T> that I can pass the First type through so that it will come out as

type Second = {
  a: { "stringValue": string },
  b: { "numberValue": number }
}

Given I can't read typeof T I can't figure out how I'd do an indexed access on the Dictionary. I can do a more manual way of a chain of conditional types, but seems very inelegant

type Dictionary<T> = T extends string ? { "stringValue": string } : { "numberValue": number }
type Second = {[Property in keyof First]: FieldValueOf<First[Property]>}

CodePudding user response:

You will need something like your Dictionary type, but the fact that they keys are named "string" and "number" has nothing to do with the types string or number, so it won't help the compiler transform string types into {stringValue: string}, without yet another mapping from "string" to string. Instead, let's dispense with key names entirely. Like this:

type Mapping =
    [string, { "stringValue": string }] |
    [number, { "numberValue": number }]

Here Mapping is a union of 2-tuples where the first element in the tuple is the "from" type, and the second element is the "to" type. You could represent this mapping in other ways (e.g., {from: From, to: To} instead of [From, To]) but this is good enough for your purposes.

Then, to map all the properties of a type T with Mapping, you can write this:

type UseMapping<T> = { [K in keyof T]: Extract<Mapping, [T[K], any]>[1] };

Here we use the Extract<T, U> utility type to find the member(s) of Mapping whose "from" type is compatible with the property type T[K], and then from that we extract its "to" type (by indexing into it with the key 1). Let's see if it works:

type Second = UseMapping<First>;

/* type Second = {
    a: {
        stringValue: string;
    };
    b: {
        numberValue: number;
    };
} */

Looks good!

Playground link to code

  • Related