Home > Enterprise >  How to create dynamic conditional types in typescript?
How to create dynamic conditional types in typescript?

Time:12-16

Im unsure if that is the correct way to title my question.

What I want to have:

type A = {
    foo: number;
}

type B = {
    bar: string;
}

ListOfTypes = [A,B]
ListOfPayloads = {
    A: A_Payload,
    B: B_Payload,
}

type TheoryType = // Insert Magic Here

const a: TheoryType = {
    type: "A",
    payload: {
        foo: 123
    }
}

const b: TheoryType = {
    type: "B",
    payload: {
        bar: "123"
    }
}

I understand that I could simplify quite easily using the following:

type TheoryType<T extends A | B> = T

Or using a function to explicitly return a specific type.

However, I just wanted to experiment with the limits of typescript and I understand some things may not be possible.

The following is the furthest I got in my experimentation:

const TYPES_NAMES = {
    A: "A",
    B: "B",
} as const;

type ObjectValues <T> = T[keyof T];

export type TYPES = ObjectValues<typeof TYPES_NAMES>;

export type PAYLOADS = {
    A: A_PAYLOAD;
    B: B_PAYLOAD;
};

export type TYPE_PAYLOADS<T extends keyof PAYLOADS> = PAYLOADS[T];

export type BODY<Key extends types> = {
    type: Key;
    payload: TYPE_PAYLOADS<Key>;
}

export type MESSAGE = {
    [Key in TYPES]: Body<Key>
}

The above is close but allows any type to match with any payload when using MESSAGE:

// Works
const body: Body<"A"> = {
foo: 123
}
// Doesnt Work
const body: Body<"A"> = {
bar: "123"
}

// Both Work
const body: Message = {
    type: "A",
    payload: {
        foo: 123
    }
}
const body: Message = {
    type: "A",
    payload: {
        bar: "123"
    }
}

CodePudding user response:

type A = {
    foo: number;
}

type B = {
    bar: string;
}

type Payload = {
    A: A
    B: B
}

type TheoryType = { [K in keyof Payload]: { type: K, payload: Payload[K] } }[keyof Payload]

const a: TheoryType = {
    type: "A",
    payload: {
        foo: 123
    }
}

const b: TheoryType = {
    type: "B",
    payload: {
        bar: "123"
    }
}

playground

  • Related