Home > OS >  How to type variable as specific type from union
How to type variable as specific type from union

Time:08-13

I am reading a JSON file with the following structure:

[
  {
    "key1" : {
       "A": 1,
       "B": 2,
       ...
    }
  },
  {
    "key1" : {
       "A": 2,
       "B": 3,
       ...
    }
  },
  {
    "key2" : {
       "A": 3,
       ...
    }
  },
  {
    "key3" : {
       "A": 4,
       ...
    }
  },
  ...
]

Some facts about the file:

  • I know that it will contain an array of various length,
  • the array will consist of specific object, which might or might not be always present but if they are, I know the structure (usually a nested object),
  • moreover, some 'objects' might have the same structure (for example key1 in the above example).

I want to define interfaces for the JSON array, so I define it like this:

export type Root = JsonObject[]

export interface JsonObject {
  [key: string]: Key1 | Key2 | Key3
}

export interface Key1 {
  A: number;
  B: number;
  ...
}

export interface Key2 {
  A: number;
  ...
}

export interface Key3 {
  A: number;
  ...
}

However when I try to loop over the array and do some action based on which object I currently loop over:

for (const member of parsedJsonFile) {

  // I check whether the first key is equal to certain value
  // and I execute certain logic based on that
  if (Object.keys(member)[0] === 'key1') {
    let memberOfTypeKeyOne: Key1 = member.key1;
    console.log(memberOfTypeKeyOne.B)
  }
}

I get the following error:

Type 'Key1 | Key2 | Key3' is not assignable to type 'Key1'.
  Type ... is missing the following properties from type ...: ...

I would like to force the variable memberOfTypeKeyOne to be of type Key1, because I know it will be, to get type hinting, type checking etc..

How can I tell TypeScript compiler, that I know this variable will be of certain type from union?

Is this even possible, or am I going completely in the wrong direction and I should rethink the whole logic?

CodePudding user response:

for (const member of parsedJsonFile) {
  if (typeof member.key1 !== 'undefined' && Object.keys(member)[0] === 'key1') {
    let memberOfTypeKeyOne: Key1 = member.key1;
    console.log(memberOfTypeKeyOne.B)
  }
}

CodePudding user response:

At the end of the day I just used type assertion, this should have occurred to me sooner.

For anyone else wondering, this is how it looks like:

for (const member of parsedJsonFile) {

  // I check whether the first key is equal to certain value
  // and I execute certain logic based on that
  if (Object.keys(member)[0] === 'key1') {
    let memberOfTypeKeyOne: Key1 = member.key1 as Key1; //            
  • Related