diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6c0e83eb339..a62e86b1ab8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13573,7 +13573,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getConstraintFromIndexedAccess(type: IndexedAccessType) { - if (isMappedTypeGenericIndexedAccess(type)) { + if (isMappedTypeGenericIndexedAccess(type) || isGenericMappedType(type.objectType)) { // 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 d2bb04de624..4c64b13436f 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.errors.txt +++ b/tests/baselines/reference/mappedTypeConstraints2.errors.txt @@ -1,10 +1,25 @@ tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(10,11): error TS2322: Type 'Mapped2[`get${K}`]' is not assignable to type '{ a: K; }'. - Type 'Mapped2[`get${string}`]' 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'. tests/cases/conformance/types/mapped/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; }'. + 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'. tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(25,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}`]'. + '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'. ==== tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts (3 errors) ==== @@ -20,7 +35,12 @@ tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(25,57): error TS2 const x: { a: K } = obj[key]; // Error ~ !!! error TS2322: Type 'Mapped2[`get${K}`]' is not assignable to type '{ a: K; }'. -!!! error TS2322: Type 'Mapped2[`get${string}`]' 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'. } type Mapped3 = { [P in K as Uppercase

]: { a: P } }; @@ -29,8 +49,14 @@ tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(25,57): error TS2 const x: { a: K } = obj[key]; // Error ~ !!! error TS2322: Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. -!!! error TS2322: Type 'Mapped3[Uppercase]' is not assignable to type '{ a: K; }'. -!!! error TS2322: Type 'Mapped3[string]' 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'. } // Repro from #47794 @@ -42,7 +68,11 @@ tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(25,57): error TS2 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: 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo[`get${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'. // Repro from #48626 @@ -65,4 +95,14 @@ tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(25,57): error TS2 } 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 442865e273a..33506284285 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.js +++ b/tests/baselines/reference/mappedTypeConstraints2.js @@ -46,6 +46,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}`]; +} //// [mappedTypeConstraints2.js] @@ -71,6 +81,9 @@ function validate(obj, bounds) { } return true; } +function genericTest(objectWithUnderscoredKeys, key) { + const shouldBeTrue = objectWithUnderscoredKeys[`_${key}`]; +} //// [mappedTypeConstraints2.d.ts] @@ -104,3 +117,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 90ee329dada..d66a412d565 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.symbols +++ b/tests/baselines/reference/mappedTypeConstraints2.symbols @@ -171,3 +171,31 @@ 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 534e02c8518..8691626d5e5 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.types +++ b/tests/baselines/reference/mappedTypeConstraints2.types @@ -128,3 +128,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}`]; +>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 d0f1703b113..b96957b7cbd 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts @@ -49,3 +49,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}`]; +}