How to create a dynamic type based on a value with Typescript

Viewed 1920

I'm building a React component that would have a different HTML tag based on a property a user passed. Here's an example:

interface Common {
    common?: number;
}

interface A extends Common {
    first?: string;
    second?: string;
    check: true;
}

interface B extends Common {
    third?: string;
    fourth?: string;
    check?: false;
}

type Test = A | B;

To test this, I'm expecting the following:

// Success
let test: Test = {
    common: 1,
    check: true,
    first: "text"
}
// Success
let test: Test = {
    common: 1,
    check: false,
    third: "text"
}
// Fail
let test: Test = {
    common: 1,
    check: true,
    third: "text"
}
// Fail
let test: Test = {
    common: 1,
    check: false,
    first: "text"
}

All of that is working, the challenge is to get type B without passing a value to check at all, like such:

let test: Test = {
    common: 1,
    first: "text", // should highlight an error because `check` is not passed
    third: "text",
}

Here is what I tried:

// Attempt 1: is to include possible values
interface B extends Common {
    third?: string;
    fourth?: string;
    check?: false | null | undefined | never | unknown | void; // tried them all
}

// Attempt 2: is not to include at all. Still didn't work
interface B extends Common {
    third?: string;
    fourth?: string;
}
2 Answers

Since Check is common between the two interfaces. Why not

interface Common {
    common?: number;
    check?: boolean;
}


interface A extends Common {
    first?: string;
    second?: string;
}

interface B extends Common {
    third?: string;
    fourth?: string;
}

type Test = A | B;

Instead ?

Related