Description
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 :
inSet1
andSet2
declarations the code works - For some reason, the code infers third generic argument of
set
(a.k.aK2 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).