From cc2ea6849273498328f7c2e5ab2225275df012b6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 Apr 2019 15:06:44 -0700 Subject: [PATCH 1/6] Fix inference from enum object type to generic mapped type --- src/compiler/checker.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 72e85b3f8a81b..bfca2519eb783 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14960,12 +14960,10 @@ namespace ts { } // If no inferences can be made to K's constraint, infer from a union of the property types // in the source to the template type X. - const valueTypes = compact([ - getIndexTypeOfType(source, IndexKind.String), - getIndexTypeOfType(source, IndexKind.Number), - ...map(getPropertiesOfType(source), getTypeOfSymbol) - ]); - inferFromTypes(getUnionType(valueTypes), getTemplateTypeFromMappedType(target)); + const indexType = source.symbol && source.symbol.flags & SymbolFlags.Enum && getEnumKind(source.symbol) === EnumKind.Literal ? + undefined : getIndexTypeOfType(source, IndexKind.String) || getIndexTypeOfType(source, IndexKind.Number); + const sourcePropsType = indexType || getUnionType(map(getPropertiesOfType(source), getTypeOfSymbol)); + inferFromTypes(sourcePropsType, getTemplateTypeFromMappedType(target)); return true; } return false; From 83f3d2ee172705f5194906616c6ef924af4188d3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 Apr 2019 15:06:55 -0700 Subject: [PATCH 2/6] Add regression test --- tests/cases/compiler/mappedToToIndexSignatureInference.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/cases/compiler/mappedToToIndexSignatureInference.ts b/tests/cases/compiler/mappedToToIndexSignatureInference.ts index 6ce63ead59cb0..ee6f71a06166a 100644 --- a/tests/cases/compiler/mappedToToIndexSignatureInference.ts +++ b/tests/cases/compiler/mappedToToIndexSignatureInference.ts @@ -1,3 +1,11 @@ declare const fn: (object: { [Key in K]: V }) => object; declare const a: { [index: string]: number }; fn(a); + +// Repro from #30218 + +declare function enumValues(e: Record): V[]; + +enum E { A = 'foo', B = 'bar' } + +let x: E[] = enumValues(E); From 436f6067ac5d078558b96bb98f5199cf93f820a1 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 Apr 2019 15:07:15 -0700 Subject: [PATCH 3/6] Accept new baselines --- .../mappedToToIndexSignatureInference.js | 14 +++++++++++ .../mappedToToIndexSignatureInference.symbols | 23 +++++++++++++++++++ .../mappedToToIndexSignatureInference.types | 19 +++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/tests/baselines/reference/mappedToToIndexSignatureInference.js b/tests/baselines/reference/mappedToToIndexSignatureInference.js index 2ea09b663a97b..03a24ab0ad98d 100644 --- a/tests/baselines/reference/mappedToToIndexSignatureInference.js +++ b/tests/baselines/reference/mappedToToIndexSignatureInference.js @@ -2,7 +2,21 @@ declare const fn: (object: { [Key in K]: V }) => object; declare const a: { [index: string]: number }; fn(a); + +// Repro from #30218 + +declare function enumValues(e: Record): V[]; + +enum E { A = 'foo', B = 'bar' } + +let x: E[] = enumValues(E); //// [mappedToToIndexSignatureInference.js] fn(a); +var E; +(function (E) { + E["A"] = "foo"; + E["B"] = "bar"; +})(E || (E = {})); +var x = enumValues(E); diff --git a/tests/baselines/reference/mappedToToIndexSignatureInference.symbols b/tests/baselines/reference/mappedToToIndexSignatureInference.symbols index d071f3f4c1cb7..d2d6f923f8706 100644 --- a/tests/baselines/reference/mappedToToIndexSignatureInference.symbols +++ b/tests/baselines/reference/mappedToToIndexSignatureInference.symbols @@ -16,3 +16,26 @@ fn(a); >fn : Symbol(fn, Decl(mappedToToIndexSignatureInference.ts, 0, 13)) >a : Symbol(a, Decl(mappedToToIndexSignatureInference.ts, 1, 13)) +// Repro from #30218 + +declare function enumValues(e: Record): V[]; +>enumValues : Symbol(enumValues, Decl(mappedToToIndexSignatureInference.ts, 2, 6)) +>K : Symbol(K, Decl(mappedToToIndexSignatureInference.ts, 6, 28)) +>V : Symbol(V, Decl(mappedToToIndexSignatureInference.ts, 6, 45)) +>e : Symbol(e, Decl(mappedToToIndexSignatureInference.ts, 6, 64)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>K : Symbol(K, Decl(mappedToToIndexSignatureInference.ts, 6, 28)) +>V : Symbol(V, Decl(mappedToToIndexSignatureInference.ts, 6, 45)) +>V : Symbol(V, Decl(mappedToToIndexSignatureInference.ts, 6, 45)) + +enum E { A = 'foo', B = 'bar' } +>E : Symbol(E, Decl(mappedToToIndexSignatureInference.ts, 6, 86)) +>A : Symbol(E.A, Decl(mappedToToIndexSignatureInference.ts, 8, 8)) +>B : Symbol(E.B, Decl(mappedToToIndexSignatureInference.ts, 8, 19)) + +let x: E[] = enumValues(E); +>x : Symbol(x, Decl(mappedToToIndexSignatureInference.ts, 10, 3)) +>E : Symbol(E, Decl(mappedToToIndexSignatureInference.ts, 6, 86)) +>enumValues : Symbol(enumValues, Decl(mappedToToIndexSignatureInference.ts, 2, 6)) +>E : Symbol(E, Decl(mappedToToIndexSignatureInference.ts, 6, 86)) + diff --git a/tests/baselines/reference/mappedToToIndexSignatureInference.types b/tests/baselines/reference/mappedToToIndexSignatureInference.types index 35b9b3565e009..21ab79e8e48b9 100644 --- a/tests/baselines/reference/mappedToToIndexSignatureInference.types +++ b/tests/baselines/reference/mappedToToIndexSignatureInference.types @@ -12,3 +12,22 @@ fn(a); >fn : (object: { [Key in K]: V; }) => object >a : { [index: string]: number; } +// Repro from #30218 + +declare function enumValues(e: Record): V[]; +>enumValues : (e: Record) => V[] +>e : Record + +enum E { A = 'foo', B = 'bar' } +>E : E +>A : E.A +>'foo' : "foo" +>B : E.B +>'bar' : "bar" + +let x: E[] = enumValues(E); +>x : E[] +>enumValues(E) : E[] +>enumValues : (e: Record) => V[] +>E : typeof E + From efa16ac11f5e06ed15097b0a81e4d7932deefab4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 16 Apr 2019 17:41:33 -0700 Subject: [PATCH 4/6] Address CR feedback --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bfca2519eb783..5e7d563bfd240 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14960,8 +14960,8 @@ namespace ts { } // If no inferences can be made to K's constraint, infer from a union of the property types // in the source to the template type X. - const indexType = source.symbol && source.symbol.flags & SymbolFlags.Enum && getEnumKind(source.symbol) === EnumKind.Literal ? - undefined : getIndexTypeOfType(source, IndexKind.String) || getIndexTypeOfType(source, IndexKind.Number); + const indexInfo = getIndexInfoOfType(source, IndexKind.String) || getIndexInfoOfType(source, IndexKind.Number); + const indexType = indexInfo && indexInfo !== enumNumberIndexInfo ? indexInfo.type : undefined; const sourcePropsType = indexType || getUnionType(map(getPropertiesOfType(source), getTypeOfSymbol)); inferFromTypes(sourcePropsType, getTemplateTypeFromMappedType(target)); return true; From 3435451dcc277b5230254af321415527aae032da Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 16 Apr 2019 18:26:24 -0700 Subject: [PATCH 5/6] Even more succinct --- src/compiler/checker.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5e7d563bfd240..e047c00d9531f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14960,9 +14960,8 @@ namespace ts { } // If no inferences can be made to K's constraint, infer from a union of the property types // in the source to the template type X. - const indexInfo = getIndexInfoOfType(source, IndexKind.String) || getIndexInfoOfType(source, IndexKind.Number); - const indexType = indexInfo && indexInfo !== enumNumberIndexInfo ? indexInfo.type : undefined; - const sourcePropsType = indexType || getUnionType(map(getPropertiesOfType(source), getTypeOfSymbol)); + const indexInfo = getIndexInfoOfType(source, IndexKind.String) || getNonEnumNumberIndexInfo(source); + const sourcePropsType = indexInfo && indexInfo.type || getUnionType(map(getPropertiesOfType(source), getTypeOfSymbol)); inferFromTypes(sourcePropsType, getTemplateTypeFromMappedType(target)); return true; } From 50fdeccd7f0380b995932151c09c27baff2591e5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 17 Apr 2019 13:58:05 -0700 Subject: [PATCH 6/6] One more iteration --- src/compiler/checker.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e047c00d9531f..5673b8b8089d4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14960,9 +14960,11 @@ namespace ts { } // If no inferences can be made to K's constraint, infer from a union of the property types // in the source to the template type X. - const indexInfo = getIndexInfoOfType(source, IndexKind.String) || getNonEnumNumberIndexInfo(source); - const sourcePropsType = indexInfo && indexInfo.type || getUnionType(map(getPropertiesOfType(source), getTypeOfSymbol)); - inferFromTypes(sourcePropsType, getTemplateTypeFromMappedType(target)); + const propTypes = map(getPropertiesOfType(source), getTypeOfSymbol); + const stringIndexType = getIndexTypeOfType(source, IndexKind.String); + const numberIndexInfo = getNonEnumNumberIndexInfo(source); + const numberIndexType = numberIndexInfo && numberIndexInfo.type; + inferFromTypes(getUnionType(append(append(propTypes, stringIndexType), numberIndexType)), getTemplateTypeFromMappedType(target)); return true; } return false;