From 82df345a4b169f85e51a251a730199419be0fe62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 19 Feb 2025 11:06:22 +0100 Subject: [PATCH 1/2] Revise behavior of mapped types with `any`/`keyof any` constraints --- src/compiler/checker.ts | 10 +++----- .../reference/mappedTypeWithAny.errors.txt | 6 +++++ .../baselines/reference/mappedTypeWithAny.js | 12 +++++++++ .../reference/mappedTypeWithAny.symbols | 17 +++++++++++++ .../reference/mappedTypeWithAny.types | 25 +++++++++++++++++-- .../types/mapped/mappedTypeWithAny.ts | 6 +++++ 6 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index abd6fd4bf2e8d..1e8250b2906c0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14127,7 +14127,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { cb(getLiteralTypeFromProperty(prop, include)); } if (type.flags & TypeFlags.Any) { - cb(stringType); + forEachType(stringsOnly ? stringType : stringNumberSymbolType, cb); } else { for (const info of getIndexInfosOfType(type)) { @@ -14166,7 +14166,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function addMemberForKeyType(keyType: Type) { const propNameType = nameType ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; - forEachType(propNameType, t => addMemberForKeyTypeWorker(keyType, t)); + forEachType(keyType.flags & TypeFlags.Any ? stringNumberSymbolType : propNameType, t => addMemberForKeyTypeWorker(keyType, t)); } function addMemberForKeyTypeWorker(keyType: Type, propNameType: Type) { @@ -14201,10 +14201,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { members.set(propName, prop); } } - else if (isValidIndexKeyType(propNameType) || propNameType.flags & (TypeFlags.Any | TypeFlags.Enum)) { - const indexKeyType = propNameType.flags & (TypeFlags.Any | TypeFlags.String) ? stringType : - propNameType.flags & (TypeFlags.Number | TypeFlags.Enum) ? numberType : - propNameType; + else if (isValidIndexKeyType(propNameType) || propNameType.flags & TypeFlags.Enum) { + const indexKeyType = propNameType.flags & (TypeFlags.Number | TypeFlags.Enum) ? numberType : propNameType; const propType = instantiateType(templateType, appendTypeMapping(type.mapper, typeParameter, keyType)); const modifiersIndexInfo = getApplicableIndexInfo(modifiersType, propNameType); const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly || diff --git a/tests/baselines/reference/mappedTypeWithAny.errors.txt b/tests/baselines/reference/mappedTypeWithAny.errors.txt index f53402fd7fcb4..e6c3c96f8276f 100644 --- a/tests/baselines/reference/mappedTypeWithAny.errors.txt +++ b/tests/baselines/reference/mappedTypeWithAny.errors.txt @@ -77,4 +77,10 @@ mappedTypeWithAny.ts(53,5): error TS2322: Type 'string[]' is not assignable to t type Evolver = any> = { [key in keyof Partial]: never; }; + + // https://github.com/microsoft/TypeScript/issues/61203 + type Obj61203 = { [k in keyof any]: number }; + declare const obj61203: Obj61203; + declare const key61203: keyof Obj61203; + obj61203[key61203]; // ok \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeWithAny.js b/tests/baselines/reference/mappedTypeWithAny.js index a01d8a6653f42..0ca780968732d 100644 --- a/tests/baselines/reference/mappedTypeWithAny.js +++ b/tests/baselines/reference/mappedTypeWithAny.js @@ -63,6 +63,12 @@ type Evolvable = { type Evolver = any> = { [key in keyof Partial]: never; }; + +// https://github.com/microsoft/TypeScript/issues/61203 +type Obj61203 = { [k in keyof any]: number }; +declare const obj61203: Obj61203; +declare const key61203: keyof Obj61203; +obj61203[key61203]; // ok //// [mappedTypeWithAny.js] @@ -79,6 +85,7 @@ function bar(arrayish, objectish, indirectArrayish) { } var abc = stringifyArray(void 0); var def = stringifyPair(void 0); +obj61203[key61203]; // ok //// [mappedTypeWithAny.d.ts] @@ -128,3 +135,8 @@ type Evolvable = { type Evolver = any> = { [key in keyof Partial]: never; }; +type Obj61203 = { + [k in keyof any]: number; +}; +declare const obj61203: Obj61203; +declare const key61203: keyof Obj61203; diff --git a/tests/baselines/reference/mappedTypeWithAny.symbols b/tests/baselines/reference/mappedTypeWithAny.symbols index b52536f518bc4..1f30122f0af27 100644 --- a/tests/baselines/reference/mappedTypeWithAny.symbols +++ b/tests/baselines/reference/mappedTypeWithAny.symbols @@ -177,3 +177,20 @@ type Evolver = any> = { }; +// https://github.com/microsoft/TypeScript/issues/61203 +type Obj61203 = { [k in keyof any]: number }; +>Obj61203 : Symbol(Obj61203, Decl(mappedTypeWithAny.ts, 61, 2)) +>k : Symbol(k, Decl(mappedTypeWithAny.ts, 64, 19)) + +declare const obj61203: Obj61203; +>obj61203 : Symbol(obj61203, Decl(mappedTypeWithAny.ts, 65, 13)) +>Obj61203 : Symbol(Obj61203, Decl(mappedTypeWithAny.ts, 61, 2)) + +declare const key61203: keyof Obj61203; +>key61203 : Symbol(key61203, Decl(mappedTypeWithAny.ts, 66, 13)) +>Obj61203 : Symbol(Obj61203, Decl(mappedTypeWithAny.ts, 61, 2)) + +obj61203[key61203]; // ok +>obj61203 : Symbol(obj61203, Decl(mappedTypeWithAny.ts, 65, 13)) +>key61203 : Symbol(key61203, Decl(mappedTypeWithAny.ts, 66, 13)) + diff --git a/tests/baselines/reference/mappedTypeWithAny.types b/tests/baselines/reference/mappedTypeWithAny.types index 587ff68bb42f3..eda08236d327d 100644 --- a/tests/baselines/reference/mappedTypeWithAny.types +++ b/tests/baselines/reference/mappedTypeWithAny.types @@ -24,8 +24,8 @@ declare let x2: { [P in string]: Item }; > : ^^^^^^^^^^^^^^^^^^^^^^ declare let x3: { [P in keyof any]: Item }; ->x3 : { [x: string]: Item; } -> : ^^^^^^^^^^^^^^^^^^^^^^ +>x3 : { [x: string]: Item; [x: number]: Item; [x: symbol]: Item; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ declare let x4: ItemMap; >x4 : ItemMap @@ -197,3 +197,24 @@ type Evolver = any> = { [key in keyof Partial]: never; }; +// https://github.com/microsoft/TypeScript/issues/61203 +type Obj61203 = { [k in keyof any]: number }; +>Obj61203 : Obj61203 +> : ^^^^^^^^ + +declare const obj61203: Obj61203; +>obj61203 : Obj61203 +> : ^^^^^^^^ + +declare const key61203: keyof Obj61203; +>key61203 : string | number | symbol +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + +obj61203[key61203]; // ok +>obj61203[key61203] : number +> : ^^^^^^ +>obj61203 : Obj61203 +> : ^^^^^^^^ +>key61203 : string | number | symbol +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts b/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts index 89c28ddafc68f..52155c6c7867d 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts @@ -63,3 +63,9 @@ type Evolvable = { type Evolver = any> = { [key in keyof Partial]: never; }; + +// https://github.com/microsoft/TypeScript/issues/61203 +type Obj61203 = { [k in keyof any]: number }; +declare const obj61203: Obj61203; +declare const key61203: keyof Obj61203; +obj61203[key61203]; // ok From a3584d1ea99eb1ce8007ff0c648b0dac1b2a8f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 25 Aug 2025 10:40:02 +0200 Subject: [PATCH 2/2] add extra test case --- .../reference/mappedTypeWithAny.errors.txt | 8 ++++ .../baselines/reference/mappedTypeWithAny.js | 18 +++++++ .../reference/mappedTypeWithAny.symbols | 33 +++++++++++++ .../reference/mappedTypeWithAny.types | 48 +++++++++++++++++++ .../types/mapped/mappedTypeWithAny.ts | 8 ++++ 5 files changed, 115 insertions(+) diff --git a/tests/baselines/reference/mappedTypeWithAny.errors.txt b/tests/baselines/reference/mappedTypeWithAny.errors.txt index e6c3c96f8276f..4652b49a4b741 100644 --- a/tests/baselines/reference/mappedTypeWithAny.errors.txt +++ b/tests/baselines/reference/mappedTypeWithAny.errors.txt @@ -83,4 +83,12 @@ mappedTypeWithAny.ts(53,5): error TS2322: Type 'string[]' is not assignable to t declare const obj61203: Obj61203; declare const key61203: keyof Obj61203; obj61203[key61203]; // ok + + + // https://github.com/microsoft/TypeScript/issues/61203#issuecomment-2703862148 + type A = { [k in keyof T]: 1 }; + declare function iDontKnow(a: T): [ A, keyof T ]; + const something: any = { a: 1, b: 2 }; + const [ o, k ] = iDontKnow(something); + const v = o[k]; // ok \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeWithAny.js b/tests/baselines/reference/mappedTypeWithAny.js index 0ca780968732d..c97401846db45 100644 --- a/tests/baselines/reference/mappedTypeWithAny.js +++ b/tests/baselines/reference/mappedTypeWithAny.js @@ -69,6 +69,14 @@ type Obj61203 = { [k in keyof any]: number }; declare const obj61203: Obj61203; declare const key61203: keyof Obj61203; obj61203[key61203]; // ok + + +// https://github.com/microsoft/TypeScript/issues/61203#issuecomment-2703862148 +type A = { [k in keyof T]: 1 }; +declare function iDontKnow(a: T): [ A, keyof T ]; +const something: any = { a: 1, b: 2 }; +const [ o, k ] = iDontKnow(something); +const v = o[k]; // ok //// [mappedTypeWithAny.js] @@ -86,6 +94,9 @@ function bar(arrayish, objectish, indirectArrayish) { var abc = stringifyArray(void 0); var def = stringifyPair(void 0); obj61203[key61203]; // ok +var something = { a: 1, b: 2 }; +var _a = iDontKnow(something), o = _a[0], k = _a[1]; +var v = o[k]; // ok //// [mappedTypeWithAny.d.ts] @@ -140,3 +151,10 @@ type Obj61203 = { }; declare const obj61203: Obj61203; declare const key61203: keyof Obj61203; +type A = { + [k in keyof T]: 1; +}; +declare function iDontKnow(a: T): [A, keyof T]; +declare const something: any; +declare const o: A, k: string | number | symbol; +declare const v: 1; diff --git a/tests/baselines/reference/mappedTypeWithAny.symbols b/tests/baselines/reference/mappedTypeWithAny.symbols index 1f30122f0af27..4b9d8696e34a4 100644 --- a/tests/baselines/reference/mappedTypeWithAny.symbols +++ b/tests/baselines/reference/mappedTypeWithAny.symbols @@ -194,3 +194,36 @@ obj61203[key61203]; // ok >obj61203 : Symbol(obj61203, Decl(mappedTypeWithAny.ts, 65, 13)) >key61203 : Symbol(key61203, Decl(mappedTypeWithAny.ts, 66, 13)) + +// https://github.com/microsoft/TypeScript/issues/61203#issuecomment-2703862148 +type A = { [k in keyof T]: 1 }; +>A : Symbol(A, Decl(mappedTypeWithAny.ts, 67, 19)) +>T : Symbol(T, Decl(mappedTypeWithAny.ts, 71, 7)) +>k : Symbol(k, Decl(mappedTypeWithAny.ts, 71, 15)) +>T : Symbol(T, Decl(mappedTypeWithAny.ts, 71, 7)) + +declare function iDontKnow(a: T): [ A, keyof T ]; +>iDontKnow : Symbol(iDontKnow, Decl(mappedTypeWithAny.ts, 71, 34)) +>T : Symbol(T, Decl(mappedTypeWithAny.ts, 72, 27)) +>a : Symbol(a, Decl(mappedTypeWithAny.ts, 72, 30)) +>T : Symbol(T, Decl(mappedTypeWithAny.ts, 72, 27)) +>A : Symbol(A, Decl(mappedTypeWithAny.ts, 67, 19)) +>T : Symbol(T, Decl(mappedTypeWithAny.ts, 72, 27)) +>T : Symbol(T, Decl(mappedTypeWithAny.ts, 72, 27)) + +const something: any = { a: 1, b: 2 }; +>something : Symbol(something, Decl(mappedTypeWithAny.ts, 73, 5)) +>a : Symbol(a, Decl(mappedTypeWithAny.ts, 73, 24)) +>b : Symbol(b, Decl(mappedTypeWithAny.ts, 73, 30)) + +const [ o, k ] = iDontKnow(something); +>o : Symbol(o, Decl(mappedTypeWithAny.ts, 74, 7)) +>k : Symbol(k, Decl(mappedTypeWithAny.ts, 74, 10)) +>iDontKnow : Symbol(iDontKnow, Decl(mappedTypeWithAny.ts, 71, 34)) +>something : Symbol(something, Decl(mappedTypeWithAny.ts, 73, 5)) + +const v = o[k]; // ok +>v : Symbol(v, Decl(mappedTypeWithAny.ts, 75, 5)) +>o : Symbol(o, Decl(mappedTypeWithAny.ts, 74, 7)) +>k : Symbol(k, Decl(mappedTypeWithAny.ts, 74, 10)) + diff --git a/tests/baselines/reference/mappedTypeWithAny.types b/tests/baselines/reference/mappedTypeWithAny.types index eda08236d327d..f6cb60e0197eb 100644 --- a/tests/baselines/reference/mappedTypeWithAny.types +++ b/tests/baselines/reference/mappedTypeWithAny.types @@ -218,3 +218,51 @@ obj61203[key61203]; // ok >key61203 : string | number | symbol > : ^^^^^^^^^^^^^^^^^^^^^^^^ + +// https://github.com/microsoft/TypeScript/issues/61203#issuecomment-2703862148 +type A = { [k in keyof T]: 1 }; +>A : A +> : ^^^^ + +declare function iDontKnow(a: T): [ A, keyof T ]; +>iDontKnow : (a: T) => [A, keyof T] +> : ^ ^^ ^^ ^^^^^ +>a : T +> : ^ + +const something: any = { a: 1, b: 2 }; +>something : any +> : ^^^ +>{ a: 1, b: 2 } : { a: number; b: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>1 : 1 +> : ^ +>b : number +> : ^^^^^^ +>2 : 2 +> : ^ + +const [ o, k ] = iDontKnow(something); +>o : A +> : ^^^^^^ +>k : string | number | symbol +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>iDontKnow(something) : [A, string | number | symbol] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>iDontKnow : (a: T) => [A, keyof T] +> : ^ ^^ ^^ ^^^^^ +>something : any +> : ^^^ + +const v = o[k]; // ok +>v : 1 +> : ^ +>o[k] : 1 +> : ^ +>o : A +> : ^^^^^^ +>k : string | number | symbol +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts b/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts index 52155c6c7867d..50d4582939da7 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeWithAny.ts @@ -69,3 +69,11 @@ type Obj61203 = { [k in keyof any]: number }; declare const obj61203: Obj61203; declare const key61203: keyof Obj61203; obj61203[key61203]; // ok + + +// https://github.com/microsoft/TypeScript/issues/61203#issuecomment-2703862148 +type A = { [k in keyof T]: 1 }; +declare function iDontKnow(a: T): [ A, keyof T ]; +const something: any = { a: 1, b: 2 }; +const [ o, k ] = iDontKnow(something); +const v = o[k]; // ok