Tommos
Tommos

Reputation: 870

Typescript type detection from if statement

Consider the following:

interface A {
  type: 'A';
  propA: 'a';
}

interface B {
  type: 'B';
  propB: 'b';
}

interface C {
  propC: 'c';
}

type OneOfAB = A | B;
type OneOfABC = A | B | C;

Typescript can infer the type from an if-statement:

const dataAB: OneOfAB = {} as any;
if (dataAB.type === 'A') {
  console.log(dataAB.propA);
}

This compiles fine, but the following does not:

const dataABC: OneOfABC = {} as any;
if ('type' in dataABC && dataABC.type === 'A') {
  console.log(dataABC.propA);
}

(Property 'type' does not exist on type 'OneOfABC'. Property 'type' does not exist on type 'C'). Apparently Typescript doesn't infer from 'type' in dataABC that the type of dataABC is not C

How to fix this? I can think of 2 ways:

function isOneOfAB(data: OneOfABC): data is OneOfAB {
  return 'type' in data;
}

const dataABC: OneOfABC = {} as any;
if (isOneOfAB(dataABC) && dataABC.type === 'A') {
  console.log(dataABC.propA);
}

OR:

const dataABC: OneOfABC = {} as any;
if ('type' in dataABC && (dataABC as any).type === 'A') {
  const dataABCcast = dataABC as A;
  console.log(dataABCcast.propA);
}

In both cases I have to say Typescript is more in the way than actually helping. In my use case there are more than three data types and they have some overlapping properties, but are also different. If I use the typeguard way as in my first example this means I will have to create many non-trivial typeguard functions to check for properties.

I'm also inclined to just drop the type checking all together and use any type. Is there any way for typescript to infer the type using something like 'property' in var?

Upvotes: 1

Views: 1267

Answers (1)

Fenton
Fenton

Reputation: 250882

I would go one small step further than you example and have a custom type guard for type A:

function isTypeA(data: any): data is A {
  return 'type' in data && data.type ==='A';
}

const dataABC: OneOfABC = {} as any;
if (isTypeA(dataABC)) {
  console.log(dataABC.propA);
}

This way, you encapsulate the whole question in one go, rather than having an if-statement that gets the answer by asking two questions.

Upvotes: 1

Related Questions