mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Always substitute indexed generic mapped type when getting constraint from indexed access (#53066)
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
tests/cases/conformance/types/mapped/mappedTypeConstraints2.ts(10,11): error TS2322: Type 'Mapped2<K>[`get${K}`]' is not assignable to type '{ a: K; }'.
|
||||
Type 'Mapped2<K>[`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<K>[Uppercase<K>]' is not assignable to type '{ a: K; }'.
|
||||
Type 'Mapped3<K>[Uppercase<string>]' is not assignable to type '{ a: K; }'.
|
||||
Type 'Mapped3<K>[string]' is not assignable to type '{ a: K; }'.
|
||||
Type '{ a: Uppercase<K>; }' is not assignable to type '{ a: K; }'.
|
||||
Types of property 'a' are incompatible.
|
||||
Type 'Uppercase<K>' is not assignable to type 'K'.
|
||||
'Uppercase<K>' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
|
||||
Type 'Uppercase<string>' is not assignable to type 'K'.
|
||||
'Uppercase<string>' 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<T>[`get${T}`]' is not assignable to type 'T'.
|
||||
'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo<T>[`get${T}`]'.
|
||||
'Foo<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${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<K>[`get${K}`]' is not assignable to type '{ a: K; }'.
|
||||
!!! error TS2322: Type 'Mapped2<K>[`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<K extends string> = { [P in K as Uppercase<P>]: { 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<K>[Uppercase<K>]' is not assignable to type '{ a: K; }'.
|
||||
!!! error TS2322: Type 'Mapped3<K>[Uppercase<string>]' is not assignable to type '{ a: K; }'.
|
||||
!!! error TS2322: Type 'Mapped3<K>[string]' is not assignable to type '{ a: K; }'.
|
||||
!!! error TS2322: Type '{ a: Uppercase<K>; }' is not assignable to type '{ a: K; }'.
|
||||
!!! error TS2322: Types of property 'a' are incompatible.
|
||||
!!! error TS2322: Type 'Uppercase<K>' is not assignable to type 'K'.
|
||||
!!! error TS2322: 'Uppercase<K>' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
|
||||
!!! error TS2322: Type 'Uppercase<string>' is not assignable to type 'K'.
|
||||
!!! error TS2322: 'Uppercase<string>' 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 extends string>(t: T, foo: Foo<T>): T => foo[`get${t}`]; // Type 'Foo<T>[`get${T}`]' is not assignable to type 'T'
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'Foo<T>[`get${T}`]' is not assignable to type 'T'.
|
||||
!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo<T>[`get${T}`]'.
|
||||
!!! error TS2322: 'Foo<T>[`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 extends string> = {
|
||||
[k in K as `_${k}`]: true;
|
||||
};
|
||||
|
||||
function genericTest<K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, key: K) {
|
||||
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`];
|
||||
}
|
||||
|
||||
@@ -46,6 +46,16 @@ function validate<T extends object>(obj: T, bounds: NumericBoundsOf<T>) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// repro from #50030
|
||||
|
||||
type ObjectWithUnderscoredKeys<K extends string> = {
|
||||
[k in K as `_${k}`]: true;
|
||||
};
|
||||
|
||||
function genericTest<K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, 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<T> = {
|
||||
[K in keyof T as T[K] extends number | undefined ? K : never]: Bounds;
|
||||
};
|
||||
declare function validate<T extends object>(obj: T, bounds: NumericBoundsOf<T>): boolean;
|
||||
type ObjectWithUnderscoredKeys<K extends string> = {
|
||||
[k in K as `_${k}`]: true;
|
||||
};
|
||||
declare function genericTest<K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, key: K): void;
|
||||
|
||||
@@ -171,3 +171,31 @@ function validate<T extends object>(obj: T, bounds: NumericBoundsOf<T>) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// repro from #50030
|
||||
|
||||
type ObjectWithUnderscoredKeys<K extends string> = {
|
||||
>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<K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, 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))
|
||||
}
|
||||
|
||||
|
||||
@@ -128,3 +128,27 @@ function validate<T extends object>(obj: T, bounds: NumericBoundsOf<T>) {
|
||||
>true : true
|
||||
}
|
||||
|
||||
// repro from #50030
|
||||
|
||||
type ObjectWithUnderscoredKeys<K extends string> = {
|
||||
>ObjectWithUnderscoredKeys : ObjectWithUnderscoredKeys<K>
|
||||
|
||||
[k in K as `_${k}`]: true;
|
||||
>true : true
|
||||
|
||||
};
|
||||
|
||||
function genericTest<K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, key: K) {
|
||||
>genericTest : <K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, key: K) => void
|
||||
>objectWithUnderscoredKeys : ObjectWithUnderscoredKeys<K>
|
||||
>key : K
|
||||
|
||||
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`];
|
||||
>shouldBeTrue : true
|
||||
>true : true
|
||||
>objectWithUnderscoredKeys[`_${key}`] : ObjectWithUnderscoredKeys<K>[`_${K}`]
|
||||
>objectWithUnderscoredKeys : ObjectWithUnderscoredKeys<K>
|
||||
>`_${key}` : `_${K}`
|
||||
>key : K
|
||||
}
|
||||
|
||||
|
||||
@@ -49,3 +49,13 @@ function validate<T extends object>(obj: T, bounds: NumericBoundsOf<T>) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// repro from #50030
|
||||
|
||||
type ObjectWithUnderscoredKeys<K extends string> = {
|
||||
[k in K as `_${k}`]: true;
|
||||
};
|
||||
|
||||
function genericTest<K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, key: K) {
|
||||
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user