From f382a68c7f78a1925cc2816832f3c329df22147d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 28 Jan 2024 10:57:16 +0100 Subject: [PATCH 1/2] Revert "Always substitute indexed generic mapped type when getting constraint from indexed access (#53066)" This reverts commit abb4052f2f639c1b19db62369ee1b0dd3ff776e7. --- src/compiler/checker.ts | 2 +- .../mappedTypeConstraints2.errors.txt | 56 +++---------------- .../reference/mappedTypeConstraints2.js | 17 ------ .../reference/mappedTypeConstraints2.symbols | 28 ---------- .../reference/mappedTypeConstraints2.types | 24 -------- .../types/mapped/mappedTypeConstraints2.ts | 10 ---- 6 files changed, 9 insertions(+), 128 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3b3d4256fecfc..aafd51d97cf0d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14230,7 +14230,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getConstraintFromIndexedAccess(type: IndexedAccessType) { - if (isMappedTypeGenericIndexedAccess(type) || isGenericMappedType(type.objectType)) { + if (isMappedTypeGenericIndexedAccess(type)) { // For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic, // we substitute an instantiation of E where P is replaced with X. return substituteIndexedMappedType(type.objectType as MappedType, type.indexType); diff --git a/tests/baselines/reference/mappedTypeConstraints2.errors.txt b/tests/baselines/reference/mappedTypeConstraints2.errors.txt index 1dd9b090f755a..1a089429b0514 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.errors.txt +++ b/tests/baselines/reference/mappedTypeConstraints2.errors.txt @@ -1,25 +1,10 @@ mappedTypeConstraints2.ts(10,11): error TS2322: Type 'Mapped2[`get${K}`]' is not assignable to type '{ a: K; }'. - Type '{ a: `get${K}`; }' is not assignable to type '{ a: K; }'. - Types of property 'a' are incompatible. - Type '`get${K}`' is not assignable to type 'K'. - '`get${K}`' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'. - Type '`get${string}`' is not assignable to type 'K'. - '`get${string}`' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'. + Type 'Mapped2[`get${string}`]' is not assignable to type '{ a: K; }'. mappedTypeConstraints2.ts(16,11): error TS2322: Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. - Type '{ a: Uppercase; }' is not assignable to type '{ a: K; }'. - Types of property 'a' are incompatible. - Type 'Uppercase' is not assignable to type 'K'. - 'Uppercase' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'. - Type 'Uppercase' is not assignable to type 'K'. - 'Uppercase' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'. - Type 'string' is not assignable to type 'K'. - 'string' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'. + Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. + Type 'Mapped3[string]' is not assignable to type '{ a: K; }'. mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. - 'Foo[`get${T}`]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'. - Type '`get${T}`' is not assignable to type 'T'. - '`get${T}`' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'. - Type '`get${string}`' is not assignable to type 'T'. - '`get${string}`' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'. + 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo[`get${T}`]'. ==== mappedTypeConstraints2.ts (3 errors) ==== @@ -35,12 +20,7 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo[`get${T}`]' is not const x: { a: K } = obj[key]; // Error ~ !!! error TS2322: Type 'Mapped2[`get${K}`]' is not assignable to type '{ a: K; }'. -!!! error TS2322: Type '{ a: `get${K}`; }' is not assignable to type '{ a: K; }'. -!!! error TS2322: Types of property 'a' are incompatible. -!!! error TS2322: Type '`get${K}`' is not assignable to type 'K'. -!!! error TS2322: '`get${K}`' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'. -!!! error TS2322: Type '`get${string}`' is not assignable to type 'K'. -!!! error TS2322: '`get${string}`' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'. +!!! error TS2322: Type 'Mapped2[`get${string}`]' is not assignable to type '{ a: K; }'. } type Mapped3 = { [P in K as Uppercase

]: { a: P } }; @@ -49,14 +29,8 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo[`get${T}`]' is not const x: { a: K } = obj[key]; // Error ~ !!! error TS2322: Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. -!!! error TS2322: Type '{ a: Uppercase; }' is not assignable to type '{ a: K; }'. -!!! error TS2322: Types of property 'a' are incompatible. -!!! error TS2322: Type 'Uppercase' is not assignable to type 'K'. -!!! error TS2322: 'Uppercase' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'. -!!! error TS2322: Type 'Uppercase' is not assignable to type 'K'. -!!! error TS2322: 'Uppercase' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'. -!!! error TS2322: Type 'string' is not assignable to type 'K'. -!!! error TS2322: 'string' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'. +!!! error TS2322: Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. +!!! error TS2322: Type 'Mapped3[string]' is not assignable to type '{ a: K; }'. } // Repro from #47794 @@ -68,11 +42,7 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo[`get${T}`]' is not const get = (t: T, foo: Foo): T => foo[`get${t}`]; // Type 'Foo[`get${T}`]' is not assignable to type 'T' ~~~~~~~~~~~~~~ !!! error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. -!!! error TS2322: 'Foo[`get${T}`]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'. -!!! error TS2322: Type '`get${T}`' is not assignable to type 'T'. -!!! error TS2322: '`get${T}`' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'. -!!! error TS2322: Type '`get${string}`' is not assignable to type 'T'. -!!! error TS2322: '`get${string}`' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string'. +!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo[`get${T}`]'. // Repro from #48626 @@ -95,14 +65,4 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo[`get${T}`]' is not } return true; } - - // repro from #50030 - - type ObjectWithUnderscoredKeys = { - [k in K as `_${k}`]: true; - }; - - function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) { - const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; - } \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeConstraints2.js b/tests/baselines/reference/mappedTypeConstraints2.js index 22b309a971524..584dd0459fd1c 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.js +++ b/tests/baselines/reference/mappedTypeConstraints2.js @@ -48,16 +48,6 @@ function validate(obj: T, bounds: NumericBoundsOf) { } return true; } - -// repro from #50030 - -type ObjectWithUnderscoredKeys = { - [k in K as `_${k}`]: true; -}; - -function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) { - const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; -} //// [mappedTypeConstraints2.js] @@ -83,9 +73,6 @@ function validate(obj, bounds) { } return true; } -function genericTest(objectWithUnderscoredKeys, key) { - const shouldBeTrue = objectWithUnderscoredKeys[`_${key}`]; -} //// [mappedTypeConstraints2.d.ts] @@ -119,7 +106,3 @@ type NumericBoundsOf = { [K in keyof T as T[K] extends number | undefined ? K : never]: Bounds; }; declare function validate(obj: T, bounds: NumericBoundsOf): boolean; -type ObjectWithUnderscoredKeys = { - [k in K as `_${k}`]: true; -}; -declare function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K): void; diff --git a/tests/baselines/reference/mappedTypeConstraints2.symbols b/tests/baselines/reference/mappedTypeConstraints2.symbols index d88f178fe7d7e..17eb64cdbd8e4 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.symbols +++ b/tests/baselines/reference/mappedTypeConstraints2.symbols @@ -173,31 +173,3 @@ function validate(obj: T, bounds: NumericBoundsOf) { return true; } -// repro from #50030 - -type ObjectWithUnderscoredKeys = { ->ObjectWithUnderscoredKeys : Symbol(ObjectWithUnderscoredKeys, Decl(mappedTypeConstraints2.ts, 46, 1)) ->K : Symbol(K, Decl(mappedTypeConstraints2.ts, 50, 31)) - - [k in K as `_${k}`]: true; ->k : Symbol(k, Decl(mappedTypeConstraints2.ts, 51, 5)) ->K : Symbol(K, Decl(mappedTypeConstraints2.ts, 50, 31)) ->k : Symbol(k, Decl(mappedTypeConstraints2.ts, 51, 5)) - -}; - -function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) { ->genericTest : Symbol(genericTest, Decl(mappedTypeConstraints2.ts, 52, 2)) ->K : Symbol(K, Decl(mappedTypeConstraints2.ts, 54, 21)) ->objectWithUnderscoredKeys : Symbol(objectWithUnderscoredKeys, Decl(mappedTypeConstraints2.ts, 54, 39)) ->ObjectWithUnderscoredKeys : Symbol(ObjectWithUnderscoredKeys, Decl(mappedTypeConstraints2.ts, 46, 1)) ->K : Symbol(K, Decl(mappedTypeConstraints2.ts, 54, 21)) ->key : Symbol(key, Decl(mappedTypeConstraints2.ts, 54, 95)) ->K : Symbol(K, Decl(mappedTypeConstraints2.ts, 54, 21)) - - const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; ->shouldBeTrue : Symbol(shouldBeTrue, Decl(mappedTypeConstraints2.ts, 55, 7)) ->objectWithUnderscoredKeys : Symbol(objectWithUnderscoredKeys, Decl(mappedTypeConstraints2.ts, 54, 39)) ->key : Symbol(key, Decl(mappedTypeConstraints2.ts, 54, 95)) -} - diff --git a/tests/baselines/reference/mappedTypeConstraints2.types b/tests/baselines/reference/mappedTypeConstraints2.types index c0f19fe9cc475..fa3d07e87757e 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.types +++ b/tests/baselines/reference/mappedTypeConstraints2.types @@ -130,27 +130,3 @@ function validate(obj: T, bounds: NumericBoundsOf) { >true : true } -// repro from #50030 - -type ObjectWithUnderscoredKeys = { ->ObjectWithUnderscoredKeys : ObjectWithUnderscoredKeys - - [k in K as `_${k}`]: true; ->true : true - -}; - -function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) { ->genericTest : (objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) => void ->objectWithUnderscoredKeys : ObjectWithUnderscoredKeys ->key : K - - const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; ->shouldBeTrue : true ->true : true ->objectWithUnderscoredKeys[`_${key}`] : ObjectWithUnderscoredKeys[`_${K}`] ->objectWithUnderscoredKeys : ObjectWithUnderscoredKeys ->`_${key}` : `_${K}` ->key : K -} - diff --git a/tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts b/tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts index b96957b7cbd83..d0f1703b1138e 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts @@ -49,13 +49,3 @@ function validate(obj: T, bounds: NumericBoundsOf) { } return true; } - -// repro from #50030 - -type ObjectWithUnderscoredKeys = { - [k in K as `_${k}`]: true; -}; - -function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) { - const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; -} From 3330257f55fd04b24d291e89b6964b49c4780c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 28 Jan 2024 10:57:55 +0100 Subject: [PATCH 2/2] Add tests --- .../mappedTypeConstraints2.errors.txt | 52 ++++- .../reference/mappedTypeConstraints2.js | 64 ++++++ .../reference/mappedTypeConstraints2.symbols | 214 ++++++++++++++---- .../reference/mappedTypeConstraints2.types | 80 +++++++ .../types/mapped/mappedTypeConstraints2.ts | 36 +++ 5 files changed, 394 insertions(+), 52 deletions(-) diff --git a/tests/baselines/reference/mappedTypeConstraints2.errors.txt b/tests/baselines/reference/mappedTypeConstraints2.errors.txt index 1a089429b0514..0d3b3244c9e66 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.errors.txt +++ b/tests/baselines/reference/mappedTypeConstraints2.errors.txt @@ -3,11 +3,16 @@ mappedTypeConstraints2.ts(10,11): error TS2322: Type 'Mapped2[`get${K}`]' is mappedTypeConstraints2.ts(16,11): error TS2322: Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. Type 'Mapped3[string]' is not assignable to type '{ a: K; }'. -mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. +mappedTypeConstraints2.ts(42,7): error TS2322: Type 'Mapped6[keyof Mapped6]' is not assignable to type '`_${string}`'. + Type 'Mapped6[string] | Mapped6[number] | Mapped6[symbol]' is not assignable to type '`_${string}`'. + Type 'Mapped6[string]' is not assignable to type '`_${string}`'. +mappedTypeConstraints2.ts(51,57): error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo[`get${T}`]'. +mappedTypeConstraints2.ts(82,9): error TS2322: Type 'ObjectWithUnderscoredKeys[`_${K}`]' is not assignable to type 'true'. + Type 'ObjectWithUnderscoredKeys[`_${string}`]' is not assignable to type 'true'. -==== mappedTypeConstraints2.ts (3 errors) ==== +==== mappedTypeConstraints2.ts (5 errors) ==== type Mapped1 = { [P in K]: { a: P } }; function f1(obj: Mapped1, key: K) { @@ -33,6 +38,36 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo[`get${T}`]' is not !!! error TS2322: Type 'Mapped3[string]' is not assignable to type '{ a: K; }'. } + type Mapped4 = { + [P in K]: P; + }; + + function f4(obj: Mapped4, key: keyof Mapped4) { + let s: `_${string}` = obj[key]; + } + + type Mapped5 = { + [P in K as P extends `_${string}` ? P : never]: P; + }; + + function f5(obj: Mapped5, key: keyof Mapped5) { + let s: `_${string}` = obj[key]; + } + + // repro from #53066#issuecomment-1913384757 + + type Mapped6 = { + [P in K as `_${P}`]: P; + }; + + function f6(obj: Mapped6, key: keyof Mapped6) { + let s: `_${string}` = obj[key]; // Error + ~ +!!! error TS2322: Type 'Mapped6[keyof Mapped6]' is not assignable to type '`_${string}`'. +!!! error TS2322: Type 'Mapped6[string] | Mapped6[number] | Mapped6[symbol]' is not assignable to type '`_${string}`'. +!!! error TS2322: Type 'Mapped6[string]' is not assignable to type '`_${string}`'. + } + // Repro from #47794 type Foo = { @@ -65,4 +100,17 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo[`get${T}`]' is not } return true; } + + // repro from #50030 + + type ObjectWithUnderscoredKeys = { + [k in K as `_${k}`]: true; + }; + + function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) { + const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not + ~~~~~~~~~~~~ +!!! error TS2322: Type 'ObjectWithUnderscoredKeys[`_${K}`]' is not assignable to type 'true'. +!!! error TS2322: Type 'ObjectWithUnderscoredKeys[`_${string}`]' is not assignable to type 'true'. + } \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeConstraints2.js b/tests/baselines/reference/mappedTypeConstraints2.js index 584dd0459fd1c..df4e0eb12d429 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.js +++ b/tests/baselines/reference/mappedTypeConstraints2.js @@ -19,6 +19,32 @@ function f3(obj: Mapped3, key: Uppercase) { const x: { a: K } = obj[key]; // Error } +type Mapped4 = { + [P in K]: P; +}; + +function f4(obj: Mapped4, key: keyof Mapped4) { + let s: `_${string}` = obj[key]; +} + +type Mapped5 = { + [P in K as P extends `_${string}` ? P : never]: P; +}; + +function f5(obj: Mapped5, key: keyof Mapped5) { + let s: `_${string}` = obj[key]; +} + +// repro from #53066#issuecomment-1913384757 + +type Mapped6 = { + [P in K as `_${P}`]: P; +}; + +function f6(obj: Mapped6, key: keyof Mapped6) { + let s: `_${string}` = obj[key]; // Error +} + // Repro from #47794 type Foo = { @@ -48,6 +74,16 @@ function validate(obj: T, bounds: NumericBoundsOf) { } return true; } + +// repro from #50030 + +type ObjectWithUnderscoredKeys = { + [k in K as `_${k}`]: true; +}; + +function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) { + const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not +} //// [mappedTypeConstraints2.js] @@ -61,6 +97,15 @@ function f2(obj, key) { function f3(obj, key) { const x = obj[key]; // Error } +function f4(obj, key) { + let s = obj[key]; +} +function f5(obj, key) { + let s = obj[key]; +} +function f6(obj, key) { + let s = obj[key]; // Error +} const get = (t, foo) => foo[`get${t}`]; // Type 'Foo[`get${T}`]' is not assignable to type 'T' function validate(obj, bounds) { for (const [key, val] of Object.entries(obj)) { @@ -73,6 +118,9 @@ function validate(obj, bounds) { } return true; } +function genericTest(objectWithUnderscoredKeys, key) { + const shouldBeTrue = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not +} //// [mappedTypeConstraints2.d.ts] @@ -94,6 +142,18 @@ type Mapped3 = { }; }; declare function f3(obj: Mapped3, key: Uppercase): void; +type Mapped4 = { + [P in K]: P; +}; +declare function f4(obj: Mapped4, key: keyof Mapped4): void; +type Mapped5 = { + [P in K as P extends `_${string}` ? P : never]: P; +}; +declare function f5(obj: Mapped5, key: keyof Mapped5): void; +type Mapped6 = { + [P in K as `_${P}`]: P; +}; +declare function f6(obj: Mapped6, key: keyof Mapped6): void; type Foo = { [RemappedT in T as `get${RemappedT}`]: RemappedT; }; @@ -106,3 +166,7 @@ type NumericBoundsOf = { [K in keyof T as T[K] extends number | undefined ? K : never]: Bounds; }; declare function validate(obj: T, bounds: NumericBoundsOf): boolean; +type ObjectWithUnderscoredKeys = { + [k in K as `_${k}`]: true; +}; +declare function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K): void; diff --git a/tests/baselines/reference/mappedTypeConstraints2.symbols b/tests/baselines/reference/mappedTypeConstraints2.symbols index 17eb64cdbd8e4..74a16d5ac1446 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.symbols +++ b/tests/baselines/reference/mappedTypeConstraints2.symbols @@ -80,96 +80,210 @@ function f3(obj: Mapped3, key: Uppercase) { >key : Symbol(key, Decl(mappedTypeConstraints2.ts, 14, 46)) } +type Mapped4 = { +>Mapped4 : Symbol(Mapped4, Decl(mappedTypeConstraints2.ts, 16, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 18, 13)) + + [P in K]: P; +>P : Symbol(P, Decl(mappedTypeConstraints2.ts, 19, 3)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 18, 13)) +>P : Symbol(P, Decl(mappedTypeConstraints2.ts, 19, 3)) + +}; + +function f4(obj: Mapped4, key: keyof Mapped4) { +>f4 : Symbol(f4, Decl(mappedTypeConstraints2.ts, 20, 2)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 22, 12)) +>obj : Symbol(obj, Decl(mappedTypeConstraints2.ts, 22, 36)) +>Mapped4 : Symbol(Mapped4, Decl(mappedTypeConstraints2.ts, 16, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 22, 12)) +>key : Symbol(key, Decl(mappedTypeConstraints2.ts, 22, 52)) +>Mapped4 : Symbol(Mapped4, Decl(mappedTypeConstraints2.ts, 16, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 22, 12)) + + let s: `_${string}` = obj[key]; +>s : Symbol(s, Decl(mappedTypeConstraints2.ts, 23, 5)) +>obj : Symbol(obj, Decl(mappedTypeConstraints2.ts, 22, 36)) +>key : Symbol(key, Decl(mappedTypeConstraints2.ts, 22, 52)) +} + +type Mapped5 = { +>Mapped5 : Symbol(Mapped5, Decl(mappedTypeConstraints2.ts, 24, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 26, 13)) + + [P in K as P extends `_${string}` ? P : never]: P; +>P : Symbol(P, Decl(mappedTypeConstraints2.ts, 27, 3)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 26, 13)) +>P : Symbol(P, Decl(mappedTypeConstraints2.ts, 27, 3)) +>P : Symbol(P, Decl(mappedTypeConstraints2.ts, 27, 3)) +>P : Symbol(P, Decl(mappedTypeConstraints2.ts, 27, 3)) + +}; + +function f5(obj: Mapped5, key: keyof Mapped5) { +>f5 : Symbol(f5, Decl(mappedTypeConstraints2.ts, 28, 2)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 30, 12)) +>obj : Symbol(obj, Decl(mappedTypeConstraints2.ts, 30, 30)) +>Mapped5 : Symbol(Mapped5, Decl(mappedTypeConstraints2.ts, 24, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 30, 12)) +>key : Symbol(key, Decl(mappedTypeConstraints2.ts, 30, 46)) +>Mapped5 : Symbol(Mapped5, Decl(mappedTypeConstraints2.ts, 24, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 30, 12)) + + let s: `_${string}` = obj[key]; +>s : Symbol(s, Decl(mappedTypeConstraints2.ts, 31, 5)) +>obj : Symbol(obj, Decl(mappedTypeConstraints2.ts, 30, 30)) +>key : Symbol(key, Decl(mappedTypeConstraints2.ts, 30, 46)) +} + +// repro from #53066#issuecomment-1913384757 + +type Mapped6 = { +>Mapped6 : Symbol(Mapped6, Decl(mappedTypeConstraints2.ts, 32, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 36, 13)) + + [P in K as `_${P}`]: P; +>P : Symbol(P, Decl(mappedTypeConstraints2.ts, 37, 3)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 36, 13)) +>P : Symbol(P, Decl(mappedTypeConstraints2.ts, 37, 3)) +>P : Symbol(P, Decl(mappedTypeConstraints2.ts, 37, 3)) + +}; + +function f6(obj: Mapped6, key: keyof Mapped6) { +>f6 : Symbol(f6, Decl(mappedTypeConstraints2.ts, 38, 2)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 40, 12)) +>obj : Symbol(obj, Decl(mappedTypeConstraints2.ts, 40, 30)) +>Mapped6 : Symbol(Mapped6, Decl(mappedTypeConstraints2.ts, 32, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 40, 12)) +>key : Symbol(key, Decl(mappedTypeConstraints2.ts, 40, 46)) +>Mapped6 : Symbol(Mapped6, Decl(mappedTypeConstraints2.ts, 32, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 40, 12)) + + let s: `_${string}` = obj[key]; // Error +>s : Symbol(s, Decl(mappedTypeConstraints2.ts, 41, 5)) +>obj : Symbol(obj, Decl(mappedTypeConstraints2.ts, 40, 30)) +>key : Symbol(key, Decl(mappedTypeConstraints2.ts, 40, 46)) +} + // Repro from #47794 type Foo = { ->Foo : Symbol(Foo, Decl(mappedTypeConstraints2.ts, 16, 1)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 20, 9)) +>Foo : Symbol(Foo, Decl(mappedTypeConstraints2.ts, 42, 1)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 46, 9)) [RemappedT in T as `get${RemappedT}`]: RemappedT; ->RemappedT : Symbol(RemappedT, Decl(mappedTypeConstraints2.ts, 21, 5)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 20, 9)) ->RemappedT : Symbol(RemappedT, Decl(mappedTypeConstraints2.ts, 21, 5)) ->RemappedT : Symbol(RemappedT, Decl(mappedTypeConstraints2.ts, 21, 5)) +>RemappedT : Symbol(RemappedT, Decl(mappedTypeConstraints2.ts, 47, 5)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 46, 9)) +>RemappedT : Symbol(RemappedT, Decl(mappedTypeConstraints2.ts, 47, 5)) +>RemappedT : Symbol(RemappedT, Decl(mappedTypeConstraints2.ts, 47, 5)) }; const get = (t: T, foo: Foo): T => foo[`get${t}`]; // Type 'Foo[`get${T}`]' is not assignable to type 'T' ->get : Symbol(get, Decl(mappedTypeConstraints2.ts, 24, 5)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 24, 13)) ->t : Symbol(t, Decl(mappedTypeConstraints2.ts, 24, 31)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 24, 13)) ->foo : Symbol(foo, Decl(mappedTypeConstraints2.ts, 24, 36)) ->Foo : Symbol(Foo, Decl(mappedTypeConstraints2.ts, 16, 1)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 24, 13)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 24, 13)) ->foo : Symbol(foo, Decl(mappedTypeConstraints2.ts, 24, 36)) ->t : Symbol(t, Decl(mappedTypeConstraints2.ts, 24, 31)) +>get : Symbol(get, Decl(mappedTypeConstraints2.ts, 50, 5)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 50, 13)) +>t : Symbol(t, Decl(mappedTypeConstraints2.ts, 50, 31)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 50, 13)) +>foo : Symbol(foo, Decl(mappedTypeConstraints2.ts, 50, 36)) +>Foo : Symbol(Foo, Decl(mappedTypeConstraints2.ts, 42, 1)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 50, 13)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 50, 13)) +>foo : Symbol(foo, Decl(mappedTypeConstraints2.ts, 50, 36)) +>t : Symbol(t, Decl(mappedTypeConstraints2.ts, 50, 31)) // Repro from #48626 interface Bounds { ->Bounds : Symbol(Bounds, Decl(mappedTypeConstraints2.ts, 24, 71)) +>Bounds : Symbol(Bounds, Decl(mappedTypeConstraints2.ts, 50, 71)) min: number; ->min : Symbol(Bounds.min, Decl(mappedTypeConstraints2.ts, 28, 18)) +>min : Symbol(Bounds.min, Decl(mappedTypeConstraints2.ts, 54, 18)) max: number; ->max : Symbol(Bounds.max, Decl(mappedTypeConstraints2.ts, 29, 16)) +>max : Symbol(Bounds.max, Decl(mappedTypeConstraints2.ts, 55, 16)) } type NumericBoundsOf = { ->NumericBoundsOf : Symbol(NumericBoundsOf, Decl(mappedTypeConstraints2.ts, 31, 1)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 33, 21)) +>NumericBoundsOf : Symbol(NumericBoundsOf, Decl(mappedTypeConstraints2.ts, 57, 1)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 59, 21)) [K in keyof T as T[K] extends number | undefined ? K : never]: Bounds; ->K : Symbol(K, Decl(mappedTypeConstraints2.ts, 34, 5)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 33, 21)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 33, 21)) ->K : Symbol(K, Decl(mappedTypeConstraints2.ts, 34, 5)) ->K : Symbol(K, Decl(mappedTypeConstraints2.ts, 34, 5)) ->Bounds : Symbol(Bounds, Decl(mappedTypeConstraints2.ts, 24, 71)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 60, 5)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 59, 21)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 59, 21)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 60, 5)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 60, 5)) +>Bounds : Symbol(Bounds, Decl(mappedTypeConstraints2.ts, 50, 71)) } function validate(obj: T, bounds: NumericBoundsOf) { ->validate : Symbol(validate, Decl(mappedTypeConstraints2.ts, 35, 1)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 37, 18)) ->obj : Symbol(obj, Decl(mappedTypeConstraints2.ts, 37, 36)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 37, 18)) ->bounds : Symbol(bounds, Decl(mappedTypeConstraints2.ts, 37, 43)) ->NumericBoundsOf : Symbol(NumericBoundsOf, Decl(mappedTypeConstraints2.ts, 31, 1)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 37, 18)) +>validate : Symbol(validate, Decl(mappedTypeConstraints2.ts, 61, 1)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 63, 18)) +>obj : Symbol(obj, Decl(mappedTypeConstraints2.ts, 63, 36)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 63, 18)) +>bounds : Symbol(bounds, Decl(mappedTypeConstraints2.ts, 63, 43)) +>NumericBoundsOf : Symbol(NumericBoundsOf, Decl(mappedTypeConstraints2.ts, 57, 1)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 63, 18)) for (const [key, val] of Object.entries(obj)) { ->key : Symbol(key, Decl(mappedTypeConstraints2.ts, 38, 16)) ->val : Symbol(val, Decl(mappedTypeConstraints2.ts, 38, 20)) +>key : Symbol(key, Decl(mappedTypeConstraints2.ts, 64, 16)) +>val : Symbol(val, Decl(mappedTypeConstraints2.ts, 64, 20)) >Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) >Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --)) ->obj : Symbol(obj, Decl(mappedTypeConstraints2.ts, 37, 36)) +>obj : Symbol(obj, Decl(mappedTypeConstraints2.ts, 63, 36)) const boundsForKey = bounds[key as keyof NumericBoundsOf]; ->boundsForKey : Symbol(boundsForKey, Decl(mappedTypeConstraints2.ts, 39, 13)) ->bounds : Symbol(bounds, Decl(mappedTypeConstraints2.ts, 37, 43)) ->key : Symbol(key, Decl(mappedTypeConstraints2.ts, 38, 16)) ->NumericBoundsOf : Symbol(NumericBoundsOf, Decl(mappedTypeConstraints2.ts, 31, 1)) ->T : Symbol(T, Decl(mappedTypeConstraints2.ts, 37, 18)) +>boundsForKey : Symbol(boundsForKey, Decl(mappedTypeConstraints2.ts, 65, 13)) +>bounds : Symbol(bounds, Decl(mappedTypeConstraints2.ts, 63, 43)) +>key : Symbol(key, Decl(mappedTypeConstraints2.ts, 64, 16)) +>NumericBoundsOf : Symbol(NumericBoundsOf, Decl(mappedTypeConstraints2.ts, 57, 1)) +>T : Symbol(T, Decl(mappedTypeConstraints2.ts, 63, 18)) if (boundsForKey) { ->boundsForKey : Symbol(boundsForKey, Decl(mappedTypeConstraints2.ts, 39, 13)) +>boundsForKey : Symbol(boundsForKey, Decl(mappedTypeConstraints2.ts, 65, 13)) const { min, max } = boundsForKey; ->min : Symbol(min, Decl(mappedTypeConstraints2.ts, 41, 19)) ->max : Symbol(max, Decl(mappedTypeConstraints2.ts, 41, 24)) ->boundsForKey : Symbol(boundsForKey, Decl(mappedTypeConstraints2.ts, 39, 13)) +>min : Symbol(min, Decl(mappedTypeConstraints2.ts, 67, 19)) +>max : Symbol(max, Decl(mappedTypeConstraints2.ts, 67, 24)) +>boundsForKey : Symbol(boundsForKey, Decl(mappedTypeConstraints2.ts, 65, 13)) if (min > val || max < val) return false; ->min : Symbol(min, Decl(mappedTypeConstraints2.ts, 41, 19)) ->val : Symbol(val, Decl(mappedTypeConstraints2.ts, 38, 20)) ->max : Symbol(max, Decl(mappedTypeConstraints2.ts, 41, 24)) ->val : Symbol(val, Decl(mappedTypeConstraints2.ts, 38, 20)) +>min : Symbol(min, Decl(mappedTypeConstraints2.ts, 67, 19)) +>val : Symbol(val, Decl(mappedTypeConstraints2.ts, 64, 20)) +>max : Symbol(max, Decl(mappedTypeConstraints2.ts, 67, 24)) +>val : Symbol(val, Decl(mappedTypeConstraints2.ts, 64, 20)) } } return true; } +// repro from #50030 + +type ObjectWithUnderscoredKeys = { +>ObjectWithUnderscoredKeys : Symbol(ObjectWithUnderscoredKeys, Decl(mappedTypeConstraints2.ts, 72, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 76, 31)) + + [k in K as `_${k}`]: true; +>k : Symbol(k, Decl(mappedTypeConstraints2.ts, 77, 5)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 76, 31)) +>k : Symbol(k, Decl(mappedTypeConstraints2.ts, 77, 5)) + +}; + +function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) { +>genericTest : Symbol(genericTest, Decl(mappedTypeConstraints2.ts, 78, 2)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 80, 21)) +>objectWithUnderscoredKeys : Symbol(objectWithUnderscoredKeys, Decl(mappedTypeConstraints2.ts, 80, 39)) +>ObjectWithUnderscoredKeys : Symbol(ObjectWithUnderscoredKeys, Decl(mappedTypeConstraints2.ts, 72, 1)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 80, 21)) +>key : Symbol(key, Decl(mappedTypeConstraints2.ts, 80, 95)) +>K : Symbol(K, Decl(mappedTypeConstraints2.ts, 80, 21)) + + const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not +>shouldBeTrue : Symbol(shouldBeTrue, Decl(mappedTypeConstraints2.ts, 81, 7)) +>objectWithUnderscoredKeys : Symbol(objectWithUnderscoredKeys, Decl(mappedTypeConstraints2.ts, 80, 39)) +>key : Symbol(key, Decl(mappedTypeConstraints2.ts, 80, 95)) +} + diff --git a/tests/baselines/reference/mappedTypeConstraints2.types b/tests/baselines/reference/mappedTypeConstraints2.types index fa3d07e87757e..9956b8f7738f6 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.types +++ b/tests/baselines/reference/mappedTypeConstraints2.types @@ -52,6 +52,62 @@ function f3(obj: Mapped3, key: Uppercase) { >key : Uppercase } +type Mapped4 = { +>Mapped4 : Mapped4 + + [P in K]: P; +}; + +function f4(obj: Mapped4, key: keyof Mapped4) { +>f4 : (obj: Mapped4, key: keyof Mapped4) => void +>obj : Mapped4 +>key : K + + let s: `_${string}` = obj[key]; +>s : `_${string}` +>obj[key] : Mapped4[K] +>obj : Mapped4 +>key : K +} + +type Mapped5 = { +>Mapped5 : Mapped5 + + [P in K as P extends `_${string}` ? P : never]: P; +}; + +function f5(obj: Mapped5, key: keyof Mapped5) { +>f5 : (obj: Mapped5, key: keyof Mapped5) => void +>obj : Mapped5 +>key : K extends `_${string}` ? K : never + + let s: `_${string}` = obj[key]; +>s : `_${string}` +>obj[key] : Mapped5[K extends `_${string}` ? K : never] +>obj : Mapped5 +>key : K extends `_${string}` ? K : never +} + +// repro from #53066#issuecomment-1913384757 + +type Mapped6 = { +>Mapped6 : Mapped6 + + [P in K as `_${P}`]: P; +}; + +function f6(obj: Mapped6, key: keyof Mapped6) { +>f6 : (obj: Mapped6, key: keyof Mapped6) => void +>obj : Mapped6 +>key : keyof Mapped6 + + let s: `_${string}` = obj[key]; // Error +>s : `_${string}` +>obj[key] : Mapped6[keyof Mapped6] +>obj : Mapped6 +>key : keyof Mapped6 +} + // Repro from #47794 type Foo = { @@ -130,3 +186,27 @@ function validate(obj: T, bounds: NumericBoundsOf) { >true : true } +// repro from #50030 + +type ObjectWithUnderscoredKeys = { +>ObjectWithUnderscoredKeys : ObjectWithUnderscoredKeys + + [k in K as `_${k}`]: true; +>true : true + +}; + +function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) { +>genericTest : (objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) => void +>objectWithUnderscoredKeys : ObjectWithUnderscoredKeys +>key : K + + const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not +>shouldBeTrue : true +>true : true +>objectWithUnderscoredKeys[`_${key}`] : ObjectWithUnderscoredKeys[`_${K}`] +>objectWithUnderscoredKeys : ObjectWithUnderscoredKeys +>`_${key}` : `_${K}` +>key : K +} + diff --git a/tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts b/tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts index d0f1703b1138e..250be640f631e 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts @@ -20,6 +20,32 @@ function f3(obj: Mapped3, key: Uppercase) { const x: { a: K } = obj[key]; // Error } +type Mapped4 = { + [P in K]: P; +}; + +function f4(obj: Mapped4, key: keyof Mapped4) { + let s: `_${string}` = obj[key]; +} + +type Mapped5 = { + [P in K as P extends `_${string}` ? P : never]: P; +}; + +function f5(obj: Mapped5, key: keyof Mapped5) { + let s: `_${string}` = obj[key]; +} + +// repro from #53066#issuecomment-1913384757 + +type Mapped6 = { + [P in K as `_${P}`]: P; +}; + +function f6(obj: Mapped6, key: keyof Mapped6) { + let s: `_${string}` = obj[key]; // Error +} + // Repro from #47794 type Foo = { @@ -49,3 +75,13 @@ function validate(obj: T, bounds: NumericBoundsOf) { } return true; } + +// repro from #50030 + +type ObjectWithUnderscoredKeys = { + [k in K as `_${k}`]: true; +}; + +function genericTest(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys, key: K) { + const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not +}