From da32f2b4f1884a235d80e3dc3fa86b413b6f5224 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 29 Mar 2018 09:36:28 -0700 Subject: [PATCH 1/4] Fix formatting --- src/compiler/checker.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fe29a7a3f13..b7b5dff3e9d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8344,17 +8344,17 @@ namespace ts { // resolution of the conditional type such that a later instantiation will properly distribute // over union types. const isDeferred = root.isDistributive && maybeTypeOfKind(checkType, TypeFlags.Instantiable); - let combinedMapper: TypeMapper; - if (root.inferTypeParameters) { - const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None); + let combinedMapper: TypeMapper; + if (root.inferTypeParameters) { + const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None); if (!isDeferred) { // We don't want inferences from constraints as they may cause us to eagerly resolve the // conditional type instead of deferring resolution. Also, we always want strict function // types rules (i.e. proper contravariance) for inferences. inferTypes(context.inferences, checkType, extendsType, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); } - combinedMapper = combineTypeMappers(mapper, context); - } + combinedMapper = combineTypeMappers(mapper, context); + } if (!isDeferred) { // Return union of trueType and falseType for 'any' since it matches anything if (checkType.flags & TypeFlags.Any) { From 1575b7a77ebe402822b62825a33bbf224a9874fb Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 29 Mar 2018 10:16:31 -0700 Subject: [PATCH 2/4] Fix parent node walk termination condition in getConstrainedTypeVariable --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b7b5dff3e9d..30ffa37e1eb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7395,7 +7395,7 @@ namespace ts { function getConstrainedTypeVariable(typeVariable: TypeVariable, node: Node) { let constraints: Type[]; - while (isPartOfTypeNode(node)) { + while (node && !isStatement(node)) { const parent = node.parent; if (parent.kind === SyntaxKind.ConditionalType && node === (parent).trueType) { const constraint = getImpliedConstraint(typeVariable, (parent).checkType, (parent).extendsType); From bd442b7e52bce290b9b8427708981992f47cf739 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 29 Mar 2018 10:22:11 -0700 Subject: [PATCH 3/4] Add regression test --- .../types/conditional/conditionalTypes1.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/cases/conformance/types/conditional/conditionalTypes1.ts b/tests/cases/conformance/types/conditional/conditionalTypes1.ts index 8aa524ba818..638cf473e19 100644 --- a/tests/cases/conformance/types/conditional/conditionalTypes1.ts +++ b/tests/cases/conformance/types/conditional/conditionalTypes1.ts @@ -341,3 +341,15 @@ declare interface ExtractFooBar { } type Extracted = { [K in keyof Struct]: Struct[K] extends FooBar ? ExtractFooBar : Struct[K]; } + +// Repro from #22985 + +type RecursivePartial = { + [P in keyof T]?: T[P] extends Array ? {[index: number]: RecursivePartial} : + T[P] extends object ? RecursivePartial : T[P]; +}; + +declare function assign(o: T, a: RecursivePartial): void; + +var a = {o: 1, b: 2, c: [{a: 1, c: '213'}]} +assign(a, {o: 2, c: {0: {a: 2, c: '213123'}}}) From f1bb530a3a4f1f3a8b24fc2502d5518ef80b4ebb Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 29 Mar 2018 10:22:20 -0700 Subject: [PATCH 4/4] Accept new baselines --- .../reference/conditionalTypes1.errors.txt | 12 ++++ .../baselines/reference/conditionalTypes1.js | 28 ++++++++ .../reference/conditionalTypes1.symbols | 54 +++++++++++++++ .../reference/conditionalTypes1.types | 68 +++++++++++++++++++ 4 files changed, 162 insertions(+) diff --git a/tests/baselines/reference/conditionalTypes1.errors.txt b/tests/baselines/reference/conditionalTypes1.errors.txt index de06eeb832b..9599cc1bcba 100644 --- a/tests/baselines/reference/conditionalTypes1.errors.txt +++ b/tests/baselines/reference/conditionalTypes1.errors.txt @@ -501,4 +501,16 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS type Extracted = { [K in keyof Struct]: Struct[K] extends FooBar ? ExtractFooBar : Struct[K]; } + + // Repro from #22985 + + type RecursivePartial = { + [P in keyof T]?: T[P] extends Array ? {[index: number]: RecursivePartial} : + T[P] extends object ? RecursivePartial : T[P]; + }; + + declare function assign(o: T, a: RecursivePartial): void; + + var a = {o: 1, b: 2, c: [{a: 1, c: '213'}]} + assign(a, {o: 2, c: {0: {a: 2, c: '213123'}}}) \ No newline at end of file diff --git a/tests/baselines/reference/conditionalTypes1.js b/tests/baselines/reference/conditionalTypes1.js index 4ac1efa1868..3e5e385625b 100644 --- a/tests/baselines/reference/conditionalTypes1.js +++ b/tests/baselines/reference/conditionalTypes1.js @@ -339,6 +339,18 @@ declare interface ExtractFooBar { } type Extracted = { [K in keyof Struct]: Struct[K] extends FooBar ? ExtractFooBar : Struct[K]; } + +// Repro from #22985 + +type RecursivePartial = { + [P in keyof T]?: T[P] extends Array ? {[index: number]: RecursivePartial} : + T[P] extends object ? RecursivePartial : T[P]; +}; + +declare function assign(o: T, a: RecursivePartial): void; + +var a = {o: 1, b: 2, c: [{a: 1, c: '213'}]} +assign(a, {o: 2, c: {0: {a: 2, c: '213123'}}}) //// [conditionalTypes1.js] @@ -435,6 +447,8 @@ var f45 = function (value) { return value; }; // Error // Repro from #21863 function f50() { } +var a = { o: 1, b: 2, c: [{ a: 1, c: '213' }] }; +assign(a, { o: 2, c: { 0: { a: 2, c: '213123' } } }); //// [conditionalTypes1.d.ts] @@ -687,3 +701,17 @@ declare interface ExtractFooBar { declare type Extracted = { [K in keyof Struct]: Struct[K] extends FooBar ? ExtractFooBar : Struct[K]; }; +declare type RecursivePartial = { + [P in keyof T]?: T[P] extends Array ? { + [index: number]: RecursivePartial; + } : T[P] extends object ? RecursivePartial : T[P]; +}; +declare function assign(o: T, a: RecursivePartial): void; +declare var a: { + o: number; + b: number; + c: { + a: number; + c: string; + }[]; +}; diff --git a/tests/baselines/reference/conditionalTypes1.symbols b/tests/baselines/reference/conditionalTypes1.symbols index ae13ff75913..fb0ce83e0a7 100644 --- a/tests/baselines/reference/conditionalTypes1.symbols +++ b/tests/baselines/reference/conditionalTypes1.symbols @@ -1317,3 +1317,57 @@ type Extracted = { >K : Symbol(K, Decl(conditionalTypes1.ts, 338, 5)) } +// Repro from #22985 + +type RecursivePartial = { +>RecursivePartial : Symbol(RecursivePartial, Decl(conditionalTypes1.ts, 339, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 343, 22)) + + [P in keyof T]?: T[P] extends Array ? {[index: number]: RecursivePartial} : +>P : Symbol(P, Decl(conditionalTypes1.ts, 344, 3)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 343, 22)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 343, 22)) +>P : Symbol(P, Decl(conditionalTypes1.ts, 344, 3)) +>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>index : Symbol(index, Decl(conditionalTypes1.ts, 344, 47)) +>RecursivePartial : Symbol(RecursivePartial, Decl(conditionalTypes1.ts, 339, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 343, 22)) +>P : Symbol(P, Decl(conditionalTypes1.ts, 344, 3)) + + T[P] extends object ? RecursivePartial : T[P]; +>T : Symbol(T, Decl(conditionalTypes1.ts, 343, 22)) +>P : Symbol(P, Decl(conditionalTypes1.ts, 344, 3)) +>RecursivePartial : Symbol(RecursivePartial, Decl(conditionalTypes1.ts, 339, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 343, 22)) +>P : Symbol(P, Decl(conditionalTypes1.ts, 344, 3)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 343, 22)) +>P : Symbol(P, Decl(conditionalTypes1.ts, 344, 3)) + +}; + +declare function assign(o: T, a: RecursivePartial): void; +>assign : Symbol(assign, Decl(conditionalTypes1.ts, 346, 2)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 348, 24)) +>o : Symbol(o, Decl(conditionalTypes1.ts, 348, 27)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 348, 24)) +>a : Symbol(a, Decl(conditionalTypes1.ts, 348, 32)) +>RecursivePartial : Symbol(RecursivePartial, Decl(conditionalTypes1.ts, 339, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 348, 24)) + +var a = {o: 1, b: 2, c: [{a: 1, c: '213'}]} +>a : Symbol(a, Decl(conditionalTypes1.ts, 350, 3)) +>o : Symbol(o, Decl(conditionalTypes1.ts, 350, 9)) +>b : Symbol(b, Decl(conditionalTypes1.ts, 350, 14)) +>c : Symbol(c, Decl(conditionalTypes1.ts, 350, 20)) +>a : Symbol(a, Decl(conditionalTypes1.ts, 350, 26)) +>c : Symbol(c, Decl(conditionalTypes1.ts, 350, 31)) + +assign(a, {o: 2, c: {0: {a: 2, c: '213123'}}}) +>assign : Symbol(assign, Decl(conditionalTypes1.ts, 346, 2)) +>a : Symbol(a, Decl(conditionalTypes1.ts, 350, 3)) +>o : Symbol(o, Decl(conditionalTypes1.ts, 351, 11)) +>c : Symbol(c, Decl(conditionalTypes1.ts, 351, 16)) +>0 : Symbol(0, Decl(conditionalTypes1.ts, 351, 21)) +>a : Symbol(a, Decl(conditionalTypes1.ts, 351, 25)) +>c : Symbol(c, Decl(conditionalTypes1.ts, 351, 30)) + diff --git a/tests/baselines/reference/conditionalTypes1.types b/tests/baselines/reference/conditionalTypes1.types index 538d8d75a07..2ba376781a5 100644 --- a/tests/baselines/reference/conditionalTypes1.types +++ b/tests/baselines/reference/conditionalTypes1.types @@ -1474,3 +1474,71 @@ type Extracted = { >K : K } +// Repro from #22985 + +type RecursivePartial = { +>RecursivePartial : RecursivePartial +>T : T + + [P in keyof T]?: T[P] extends Array ? {[index: number]: RecursivePartial} : +>P : P +>T : T +>T : T +>P : P +>Array : T[] +>index : number +>RecursivePartial : RecursivePartial +>T : T +>P : P + + T[P] extends object ? RecursivePartial : T[P]; +>T : T +>P : P +>RecursivePartial : RecursivePartial +>T : T +>P : P +>T : T +>P : P + +}; + +declare function assign(o: T, a: RecursivePartial): void; +>assign : (o: T, a: RecursivePartial) => void +>T : T +>o : T +>T : T +>a : RecursivePartial +>RecursivePartial : RecursivePartial +>T : T + +var a = {o: 1, b: 2, c: [{a: 1, c: '213'}]} +>a : { o: number; b: number; c: { a: number; c: string; }[]; } +>{o: 1, b: 2, c: [{a: 1, c: '213'}]} : { o: number; b: number; c: { a: number; c: string; }[]; } +>o : number +>1 : 1 +>b : number +>2 : 2 +>c : { a: number; c: string; }[] +>[{a: 1, c: '213'}] : { a: number; c: string; }[] +>{a: 1, c: '213'} : { a: number; c: string; } +>a : number +>1 : 1 +>c : string +>'213' : "213" + +assign(a, {o: 2, c: {0: {a: 2, c: '213123'}}}) +>assign(a, {o: 2, c: {0: {a: 2, c: '213123'}}}) : void +>assign : (o: T, a: RecursivePartial) => void +>a : { o: number; b: number; c: { a: number; c: string; }[]; } +>{o: 2, c: {0: {a: 2, c: '213123'}}} : { o: number; c: { 0: { a: number; c: string; }; }; } +>o : number +>2 : 2 +>c : { 0: { a: number; c: string; }; } +>{0: {a: 2, c: '213123'}} : { 0: { a: number; c: string; }; } +>0 : { a: number; c: string; } +>{a: 2, c: '213123'} : { a: number; c: string; } +>a : number +>2 : 2 +>c : string +>'213123' : "213123" +