Cosmin Leferman
Cosmin Leferman

Reputation: 158

Typescript: Generics, infer the value of object if key is given

Let's say we have some kind of dispatch functions that tries to update a certain prop on an object. Is it possible to have proper type inference in the following scenario?

type EntityA = {
  name: string;
  id: number
}

type EntityB = {
  id: number;
  test1: number;
  test2: string;
  test3: number;
  test4: string;
}

type EntityAction<T> = {
  [K in keyof T]-?:
  | {
    type: 'UPDATE_ENTITY';
    payload: T;
  } |
  {
    type: 'UPDATE_PROP';
    propName: K;
    payload: T[K];
  };
}[keyof T];

function dispatch<T>(action: EntityAction<T>) {
  // omitted logic because it's not relevant
  console.log(action);
}

dispatch<EntityA>({
  type: 'UPDATE_PROP',
  propName: 'name',
});

dispatch<EntityB>({
  type: 'UPDATE_PROP',
  propName: 'test4',
  payload: ''
})

Playground here

I managed to infer the types based on a reply found here (Thanks @jcalz) but as soon as I have more than 1 prop in a type it doesn't work correctly.

Given EntityA, if i dispatch the following:

dispatch<EntityA>({ type: 'UPDATE_PROP',propName: 'id' })

it correctly lets me know that the prop payload is missing However, if I pass

dispatch<EntityA>({ type: 'UPDATE_PROP',propName: 'name' })

It tells me that Type '"name"' is not assignable to type '"id"'. (or whatever the last prop in the type is).

Any idea if this can be "fixed" to properly infer the type of payload? Is it even possible in this setup? It seems to work if EntityAction as:

export type EntityAction<T> = {
  [K in keyof T]-?:
  {
    type: 'UPDATE_PROP';
    propName: K;
    payload: T[K];
  };
}[keyof T];

Upvotes: 0

Views: 76

Answers (1)

jcalz
jcalz

Reputation: 330411

This looks like a known bug, reported at microsoft/TypeScript#46374, in which an "incomplete" value assigned to a discriminated union yields a compiler error which complains about the wrong property.

It looks like it was introduced in TypeScript 3.9, sometime between [email protected] and [email protected], which leads me to believe that it was probably caused by the work done in microsoft/TypeScript#37589, "Disallow partial matches for discriminant properties when generating error messages", which changed the way discriminated union error messages were generated, fixing a different bug but apparently causing this one.

Anyway, the bug is currently scheduled to be fixed for TypeScript 5.1, but it has been rescheduled several times already, so it's not clear if this will actually happen.

Upvotes: 1

Related Questions