0

I'm trying to define a type which should be either Base or Base with additional fields. My code looks like this:

interface Base {
  id: string,
}

interface Extra {
  firstName: string,
  lastName: string,
}

type Human = Base | (Base & Extra);

const validBase: Base = {id: "123"};
const validHuman: Human = {id: "123", firstName: "Seppo", lastName: "Taalasmaa"};

This works as expected. But if I create an invalid Human, which has only firstName but no lastName, it is still considered to be a valid Human. Why?

const shouldBeInvalid: Human = {id: "123", firstName: "Seppo"}; // Works, why??
Jarzka
  • 755
  • 7
  • 22
  • `Human` needs to be a "`Base`" or a "`Base` and `Extra`". In your example it complies with the first case, so it's deemed as valid. – Alejandro Dec 12 '22 at 12:34
  • @Alejandro I think `type Human = Base | (Base & Extra)` should be equal to `"Base" or a "Base and Extra"`. That being said, `{id: "123", firstName: "Seppo"}` does not satisfy `Base` since `firstName` is not mentioned there. It also does not satisfy `(Base & Extra)` since `lastName` is missing. – Jarzka Dec 12 '22 at 12:52
  • It might seem weird, but `{id: "123", firstName: "Sepp"}` *does* satisfy `Base`. Excess properties do not invalidate a type's assignability. It is confusing because TS does do some excess property checking, but only on *object literals*, and only in certain circumstances (and unions where the excess properties exist on the other members of the union do not count). See the answers to the linked questions for more information. – jcalz Dec 12 '22 at 17:00

0 Answers0