2

I want to define a Person type, as such:

interface Person  {
    gender: 'male'|'female';
    pants?: string;
    skirt?: string;
}

However, I want to make it more specific, whenever the gender=male, then pants must exist, or if gender=female, then skirt must exist, something like this:

interface Person {                Person {
    gender: 'male';     [OR]          gender: 'female';
    pants: string;                    skirt: string;
}                                  }

Both are similar object, except have few keys different. Is it possible? Is this a good practice in typing an object?

I hope I can do something like:

interface Person {
    gender: 'male'|'female'|'elf'|'undead';
    head?: string;
    pants?: string exists if gender='male';
    skirt?: string exists if gender='female';
    leg?: string;
    tail?: string exists if gender='elf'|'undead';
}

Haha... Probably I think too much...

7
  • 2
    Perhaps by extending the interface to have interface MalePerson extends Person or interface FemalePerson extends Person? Commented Nov 1, 2018 at 16:55
  • Is that the only way? Hmmm... because if I extend the interface, I probably have many sub-interface, then my .ts file will full with import interface statement... Hmmm... Commented Nov 1, 2018 at 17:00
  • 1
    you can have an index.ts file in the models folder and import all the required classes/interfaces there and import only the models folder in your component. Commented Nov 1, 2018 at 17:15
  • ok, then i will use extends and apply index.ts import... thanks everyone... Commented Nov 1, 2018 at 17:21
  • 2
    It seems that you want a discriminated union, where gender is the discriminant. Is there something about that solution which wouldn't work for you? (And if so, can you add detail to the question?) Commented Nov 1, 2018 at 19:18

1 Answer 1

1

Despite the interface style method, you can use discriminated unions.

Below is the answer. Tested using TypeScript 3.1.3.

type Person = {
    gender: "male";
    pants: string;
} | {
    gender: "female";
    skirt: string;
};

In this case, (if I'm not mistaken), gender is known as the discriminant, it can help the compiler static analyzer to identified which type you wanted to use.

For example,

let x: Person = { 
    gender: "male",
    skirt: "red" // <-- Compile error, because when gender is "male", `skirt` does not exist
    // <-- Another error, property `pants` is missing
}

For more information, try studying discriminated unions in TypeScript.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.