Skip to content

Wrong Pick inference starting from version 3.6.0 #33468

Closed
@Siegrift

Description

@Siegrift

TypeScript Version: >3.6.0

Search Terms: Pick, Exclude, Omit

Code

type Set1<T, K1 extends keyof T> = T extends any[] ? T : Pick<T, Exclude<keyof T, K1>> & {
  [SK1 in K1]-?: Required<Pick<T, SK1>>;
}[K1];

type Set2<T, K1 extends keyof T, K2 extends keyof T[K1]> = T extends any[] ? T : Pick<T, Exclude<keyof T, K1>> & {
  [SK1 in K1]-?: Required<{
      [key in K1]: Set1<T[K1], K2>;
  }>;
}[K1];

declare function set<T, K1 extends keyof T>(source: T, path: [K1], value: T[K1]): Set1<T, K1>;

declare function set<T, K1 extends keyof T, K2 extends keyof T[K1]>(source: T, path: [K1, K2], value: T[K1][K2]): Set2<T, K1, K2>;


interface State {
  a: {
    b: string;
    c: number;
  };
  d: boolean;
}

const state: State = {
  a: {
    b: "",
    c: 0,
  },
  d: false,
};

const newState: State = set(state, ["a", 'b'], 'why'); // error

Expected behavior:
Type of the return value of set function should be assignable to State

Actual behavior:

Type 'Pick<State, "d"> & { a: (Pick<{ b: string; c: number; }, never> & Pick<{ b: string; c: number; }, "b">) | (Pick<{ b: string; c: number; }, never> & Pick<{ b: string; c: number; }, "c">); }' is not assignable to type 'State'.
  Types of property 'a' are incompatible.
    Type '(Pick<{ b: string; c: number; }, never> & Pick<{ b: string; c: number; }, "b">) | (Pick<{ b: string; c: number; }, never> & Pick<{ b: string; c: number; }, "c">)' is not assignable to type '{ b: string; c: number; }'.
      Property 'c' is missing in type 'Pick<{ b: string; c: number; }, never> & Pick<{ b: string; c: number; }, "b">' but required in type '{ b: string; c: number; }'.

Playground Link:
http://www.typescriptlang.org/play/#code/C4TwDgpgBAyhwEYA8AVANFA0gqEAewEAdgCYDOUA1hCAPYBmUKAfFALxO4HHlQCGREAG0AulAD8nAFxQACgEsAxpVQYAonkUAbAK4kISanUbosCZqwBkUAN4BYAFBQoQmNijyiZkQFpxMgCUIAEcdeQAnCBIkBWVVWGwLAG5HAF8hbBEUh0dQSFh4ACZ493xCUgojBiYMTEKuct4qkwyEEVYOFAaeCgFhMUkumViVUw1tPQNmmrMLKGt7Jxc3HE9vP0CQsMjoxed9lyMPL0yZOERUVpFawuZs51S7tKvsx31tPkioeh0iRWB5LQvGR4CUcGUelQaNUWAAKMi0HThRQQGSmMB8YAACxkVwwADc+LpUUwrgBKM7wZCmRKvBzvLSfaA-P4AoFQEHAMHdCpQ4wzOo8prQlqZZjwxHIknozE4lzYG7XKCE4loq4ZQoiCkFYDFGkIG5PHLGzyEcL0Pgo2DATHQPb8GT25wAIxkZGA4U8AHN7vtFDIiDoALbOiDhX2pX0kGTO2i0LQQATZVKORyKIHujk2whnbPQDj2viOxwHV1QABE5bQJb9MgADNWlqlG85o98iSDG5HUw500RM0QIAB3GB53O29gc+DwvMYITlvhVqAAcmdy6Vy6HWJAy7JSSAA
(Playground doesn't support >3.6.0 at this time, so there it works)

My observatioins:

  • If I remove the d property from state, the code works
  • If I remove the T extends any[] ? T : in Set1 and Set2 declarations the code works
  • For some reason, the code infers third generic argument of set (a.k.a K2 extends keyof T[K1]) as "b" | "c" which might be the issue here. However, I don't understand why it does it.
  • Tried looking at releases for 3.6.0 but I didn't see anything directly related.

Related Issues:
I tried looking for them, but it's hard to know what to search for... The closest to my problem seemed #28884, but it's not directly related (I think).

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScript

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions