mikeysee
mikeysee

Reputation: 1763

Why does type-narrowing fail in this case?

Given:

export type CommandsTypes = {
  "test-command": {
    propA: string;
    propB: number;
  };

  "test-command2": {
    propC: string;
    propD: number;
  };
};

export type Command<K extends keyof CommandsTypes> = {
  type: K;
  payload: CommandsTypes[K];
};

export type AnyCommand = Command<keyof CommandsTypes>;

Why does the following not type-narrow as expected:

function handle(command: AnyCommand) {
  if (command.type === "test-command") {
    // I would expect the type of command at this point to be
    // Command<"test-command"> 
    // But its not?
  }
}

Any ideas why Typescript isnt able to narrow the AnyCommand type above to Command<"test-command"> ?

Upvotes: 1

Views: 49

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249506

Command<keyof CommandTypes> will be equivalent to { type: keyof CommandTypes, payload :CommandTypes[keyof CommandTypes] } basically this would mean you could pair any type with any payload, which is not what you want.

You would want to build a discriminated union. Todo this we can use the distributive behavior of conditional types which will apply a type transformation over each member of the union of keys

export type AnyCommandHelper<T extends keyof CommandsTypes> =
    T extends keyof CommandsTypes? Command<T>: never
export type AnyCommand = AnyCommandHelper<keyof CommandsTypes>;

Upvotes: 1

Related Questions