diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c5787c3b29d..3273b7cb185 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15408,6 +15408,13 @@ namespace ts { }; } + function cloneInferredPartOfContext(context: InferenceContext): InferenceContext | undefined { + const inferences = filter(context.inferences, hasInferenceCandidates); + return inferences.length ? + createInferenceContextWorker(map(inferences, cloneInferenceInfo), context.signature, context.flags, context.compareTypes) : + undefined; + } + function getMapperFromContext(context: T): TypeMapper | T & undefined { return context && context.mapper; } @@ -21465,7 +21472,7 @@ namespace ts { const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags); const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper); inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType); - context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(returnContext) : undefined; + context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; } } diff --git a/tests/baselines/reference/twiceNestedKeyofIndexInference.js b/tests/baselines/reference/twiceNestedKeyofIndexInference.js new file mode 100644 index 00000000000..ed4f0c6bfb5 --- /dev/null +++ b/tests/baselines/reference/twiceNestedKeyofIndexInference.js @@ -0,0 +1,43 @@ +//// [twiceNestedKeyofIndexInference.ts] +type Set1 = T extends any[] ? T : Pick> & { + [SK1 in K1]-?: Required>; +}[K1]; + +type Set2 = T extends any[] ? T : Pick> & { + [SK1 in K1]-?: Required<{ + [key in K1]: Set1; + }>; +}[K1]; + +declare function set(source: T, path: [K1], value: T[K1]): Set1; + +declare function set(source: T, path: [K1, K2], value: T[K1][K2]): Set2; + + +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'); // shouldn't be an error + +//// [twiceNestedKeyofIndexInference.js] +var state = { + a: { + b: "", + c: 0 + }, + d: false +}; +var newState = set(state, ["a", 'b'], 'why'); // shouldn't be an error diff --git a/tests/baselines/reference/twiceNestedKeyofIndexInference.symbols b/tests/baselines/reference/twiceNestedKeyofIndexInference.symbols new file mode 100644 index 00000000000..57fa8e738b2 --- /dev/null +++ b/tests/baselines/reference/twiceNestedKeyofIndexInference.symbols @@ -0,0 +1,139 @@ +=== tests/cases/compiler/twiceNestedKeyofIndexInference.ts === +type Set1 = T extends any[] ? T : Pick> & { +>Set1 : Symbol(Set1, Decl(twiceNestedKeyofIndexInference.ts, 0, 0)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 0, 10)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 0, 12)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 0, 10)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 0, 10)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 0, 10)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 0, 10)) +>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 0, 10)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 0, 12)) + + [SK1 in K1]-?: Required>; +>SK1 : Symbol(SK1, Decl(twiceNestedKeyofIndexInference.ts, 1, 5)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 0, 12)) +>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 0, 10)) +>SK1 : Symbol(SK1, Decl(twiceNestedKeyofIndexInference.ts, 1, 5)) + +}[K1]; +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 0, 12)) + +type Set2 = T extends any[] ? T : Pick> & { +>Set2 : Symbol(Set2, Decl(twiceNestedKeyofIndexInference.ts, 2, 6)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 4, 10)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 4, 12)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 4, 10)) +>K2 : Symbol(K2, Decl(twiceNestedKeyofIndexInference.ts, 4, 32)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 4, 10)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 4, 12)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 4, 10)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 4, 10)) +>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 4, 10)) +>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 4, 10)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 4, 12)) + + [SK1 in K1]-?: Required<{ +>SK1 : Symbol(SK1, Decl(twiceNestedKeyofIndexInference.ts, 5, 5)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 4, 12)) +>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --)) + + [key in K1]: Set1; +>key : Symbol(key, Decl(twiceNestedKeyofIndexInference.ts, 6, 9)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 4, 12)) +>Set1 : Symbol(Set1, Decl(twiceNestedKeyofIndexInference.ts, 0, 0)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 4, 10)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 4, 12)) +>K2 : Symbol(K2, Decl(twiceNestedKeyofIndexInference.ts, 4, 32)) + + }>; +}[K1]; +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 4, 12)) + +declare function set(source: T, path: [K1], value: T[K1]): Set1; +>set : Symbol(set, Decl(twiceNestedKeyofIndexInference.ts, 8, 6), Decl(twiceNestedKeyofIndexInference.ts, 10, 94)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 10, 21)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 10, 23)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 10, 21)) +>source : Symbol(source, Decl(twiceNestedKeyofIndexInference.ts, 10, 44)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 10, 21)) +>path : Symbol(path, Decl(twiceNestedKeyofIndexInference.ts, 10, 54)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 10, 23)) +>value : Symbol(value, Decl(twiceNestedKeyofIndexInference.ts, 10, 66)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 10, 21)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 10, 23)) +>Set1 : Symbol(Set1, Decl(twiceNestedKeyofIndexInference.ts, 0, 0)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 10, 21)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 10, 23)) + +declare function set(source: T, path: [K1, K2], value: T[K1][K2]): Set2; +>set : Symbol(set, Decl(twiceNestedKeyofIndexInference.ts, 8, 6), Decl(twiceNestedKeyofIndexInference.ts, 10, 94)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 12, 21)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 12, 23)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 12, 21)) +>K2 : Symbol(K2, Decl(twiceNestedKeyofIndexInference.ts, 12, 43)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 12, 21)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 12, 23)) +>source : Symbol(source, Decl(twiceNestedKeyofIndexInference.ts, 12, 68)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 12, 21)) +>path : Symbol(path, Decl(twiceNestedKeyofIndexInference.ts, 12, 78)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 12, 23)) +>K2 : Symbol(K2, Decl(twiceNestedKeyofIndexInference.ts, 12, 43)) +>value : Symbol(value, Decl(twiceNestedKeyofIndexInference.ts, 12, 94)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 12, 21)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 12, 23)) +>K2 : Symbol(K2, Decl(twiceNestedKeyofIndexInference.ts, 12, 43)) +>Set2 : Symbol(Set2, Decl(twiceNestedKeyofIndexInference.ts, 2, 6)) +>T : Symbol(T, Decl(twiceNestedKeyofIndexInference.ts, 12, 21)) +>K1 : Symbol(K1, Decl(twiceNestedKeyofIndexInference.ts, 12, 23)) +>K2 : Symbol(K2, Decl(twiceNestedKeyofIndexInference.ts, 12, 43)) + + +interface State { +>State : Symbol(State, Decl(twiceNestedKeyofIndexInference.ts, 12, 130)) + + a: { +>a : Symbol(State.a, Decl(twiceNestedKeyofIndexInference.ts, 15, 17)) + + b: string; +>b : Symbol(b, Decl(twiceNestedKeyofIndexInference.ts, 16, 8)) + + c: number; +>c : Symbol(c, Decl(twiceNestedKeyofIndexInference.ts, 17, 18)) + + }; + d: boolean; +>d : Symbol(State.d, Decl(twiceNestedKeyofIndexInference.ts, 19, 6)) +} + +const state: State = { +>state : Symbol(state, Decl(twiceNestedKeyofIndexInference.ts, 23, 5)) +>State : Symbol(State, Decl(twiceNestedKeyofIndexInference.ts, 12, 130)) + + a: { +>a : Symbol(a, Decl(twiceNestedKeyofIndexInference.ts, 23, 22)) + + b: "", +>b : Symbol(b, Decl(twiceNestedKeyofIndexInference.ts, 24, 8)) + + c: 0, +>c : Symbol(c, Decl(twiceNestedKeyofIndexInference.ts, 25, 14)) + + }, + d: false, +>d : Symbol(d, Decl(twiceNestedKeyofIndexInference.ts, 27, 6)) + +}; + +const newState: State = set(state, ["a", 'b'], 'why'); // shouldn't be an error +>newState : Symbol(newState, Decl(twiceNestedKeyofIndexInference.ts, 31, 5)) +>State : Symbol(State, Decl(twiceNestedKeyofIndexInference.ts, 12, 130)) +>set : Symbol(set, Decl(twiceNestedKeyofIndexInference.ts, 8, 6), Decl(twiceNestedKeyofIndexInference.ts, 10, 94)) +>state : Symbol(state, Decl(twiceNestedKeyofIndexInference.ts, 23, 5)) + diff --git a/tests/baselines/reference/twiceNestedKeyofIndexInference.types b/tests/baselines/reference/twiceNestedKeyofIndexInference.types new file mode 100644 index 00000000000..68622038e72 --- /dev/null +++ b/tests/baselines/reference/twiceNestedKeyofIndexInference.types @@ -0,0 +1,76 @@ +=== tests/cases/compiler/twiceNestedKeyofIndexInference.ts === +type Set1 = T extends any[] ? T : Pick> & { +>Set1 : Set1 + + [SK1 in K1]-?: Required>; +}[K1]; + +type Set2 = T extends any[] ? T : Pick> & { +>Set2 : Set2 + + [SK1 in K1]-?: Required<{ + [key in K1]: Set1; + }>; +}[K1]; + +declare function set(source: T, path: [K1], value: T[K1]): Set1; +>set : { (source: T, path: [K1], value: T[K1]): Set1; (source: T, path: [K1, K2], value: T[K1][K2]): Set2; } +>source : T +>path : [K1] +>value : T[K1] + +declare function set(source: T, path: [K1, K2], value: T[K1][K2]): Set2; +>set : { (source: T, path: [K1], value: T[K1]): Set1; (source: T, path: [K1, K2], value: T[K1][K2]): Set2; } +>source : T +>path : [K1, K2] +>value : T[K1][K2] + + +interface State { + a: { +>a : { b: string; c: number; } + + b: string; +>b : string + + c: number; +>c : number + + }; + d: boolean; +>d : boolean +} + +const state: State = { +>state : State +>{ a: { b: "", c: 0, }, d: false,} : { a: { b: string; c: number; }; d: false; } + + a: { +>a : { b: string; c: number; } +>{ b: "", c: 0, } : { b: string; c: number; } + + b: "", +>b : string +>"" : "" + + c: 0, +>c : number +>0 : 0 + + }, + d: false, +>d : false +>false : false + +}; + +const newState: State = set(state, ["a", 'b'], 'why'); // shouldn't be an error +>newState : State +>set(state, ["a", 'b'], 'why') : Pick & Required<{ a: Pick<{ b: string; c: number; }, "c"> & Required>; }> +>set : { (source: T, path: [K1], value: T[K1]): Set1; (source: T, path: [K1, K2], value: T[K1][K2]): Set2; } +>state : State +>["a", 'b'] : ["a", "b"] +>"a" : "a" +>'b' : "b" +>'why' : "why" + diff --git a/tests/cases/compiler/twiceNestedKeyofIndexInference.ts b/tests/cases/compiler/twiceNestedKeyofIndexInference.ts new file mode 100644 index 00000000000..35fb39b009e --- /dev/null +++ b/tests/cases/compiler/twiceNestedKeyofIndexInference.ts @@ -0,0 +1,32 @@ +type Set1 = T extends any[] ? T : Pick> & { + [SK1 in K1]-?: Required>; +}[K1]; + +type Set2 = T extends any[] ? T : Pick> & { + [SK1 in K1]-?: Required<{ + [key in K1]: Set1; + }>; +}[K1]; + +declare function set(source: T, path: [K1], value: T[K1]): Set1; + +declare function set(source: T, path: [K1, K2], value: T[K1][K2]): Set2; + + +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'); // shouldn't be an error \ No newline at end of file