0

I am new to typescript and stuck in defining type of JSON object. In the following examples I want to define the type for myJSONObject. The required types which I defined are JSONType_1 and JSONType_2.

type RequireOnlyOne<T, Keys extends keyof T = keyof T> =
    Pick<T, Exclude<keyof T, Keys>>
    & {
      [K in Keys]-?: Required<Pick<T, K>> & Partial<Record<Exclude<Keys, K>, undefined>>
    }[Keys];

interface NetworkIdOptions {
  group?: string;
  individual?: string;
}

type NetworkId = RequireOnlyOne<NetworkIdOptions, 'group' | 'individual'>;

export interface JSONType_1 {
  networkId: NetworkId;
  tasks: Array<
  | taskInterface_1
  | taskInterface_2
  | taskInterface_3
  >;
}
export interface JSONType_2 {
  networkId: {
    group: 'myFavGroup';
  };
  tasks: Array<
  | taskInterface_4
  | taskInterface_5
  >;
}

As per this networkId can either have group key or individual key. When networkId has group key and who's value is = myFavGroup, then I want this object to be type of JSONType_2. Notice the tasks changes when group name is myFavGroup. Use case for above defined JSONType_1 & JSONType_2:

myFunc(myJSONObject: JSONType_1 | JSONType_2) {
  if (myJSONObject.networkId.group && myJSONObject.networkId.group === 'myFavGroup') {
    differentFunction(myJSONObject) // this function takes input only in `JSONType_2`.
  }
}

Inside this if condition I want myJSONObject to have JSONType_2 and not JSONType_1 | JSONType_2 types. As I want to send only JSONType_2 to a different function. Error which I get:

Argument of type 'JSONType_1 | JSONType_2' is not assignable to parameter of type 'JSONType_2'.
...
Types of property 'group' are incompatible.
Type 'string' is not assignable to type '"myFavGroup"'.

myJSONObject is received from another service who's structures are fixed. 2 Examples:

{
  networkId: {
    group: 'Desktop_group';
  };
  tasks: [
    { cmd: 'playMusic', songName: 'xyz' },
    { cmd: 'playVideo', videoName: 'abc' },
  ];
}
{
  networkId: {
    group: 'myFavGroup';
  };
  tasks: [
    { cmd: 'sendMusicList', path: '/home/user/musicFolder' },
    { cmd: 'sendFilesStats', path: '/home/user/someFolder' },
  ];
}

Notice all tasks JSON objects are also predefined and fixed. The only difference is that tasks for myFavGroup are different than any other group.

If there is a better way to code than what I am doing, I would appreciate your help in that too. Thanks in advance.

2
  • How are you declaring myJSONObject or what is the structure? May be an example? Commented Oct 16, 2020 at 10:55
  • Edited the question by adding myJSONObject examples which I receive. @MBB Commented Oct 16, 2020 at 13:38

1 Answer 1

1

Your code looks a bit dirty and I would consider some refactor, but!

// if group = 'myFavGroup' only for JSONType_2 you can exclude it for JSONType_1
interface NetworkIdOptions {
  group?: Exclude<'myFavGroup', string>; // <---
  individual?: string;
}

and

to make types compatible, you need to make group property optional for JSONType_2

export interface JSONType_2 {
  networkId: {
    group?: 'myFavGroup'; // <---
  };
}

This way after checking that networkId.group is equal to 'myFavGroup' your Typescript compiler will automagically understand that your argument is of type JSONType_2 and you can successfully pass it to the differentFunction

Another solution would be just to use type assertion:

differentFunction(myJSONObject as JSONType_2)
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Dmitry, sorry for this dirty code, I am still learning typescript. Would you like to suggest how can I make it more cleaner? Also 1st solution didn't work it throws an error on Types of property 'tasks' are incompatible. as we can see tasks are different for myFavGroup. But 2nd solution worked.

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.