Skip to content

Commit

Permalink
Revert "Always substitute indexed generic mapped type when getting co…
Browse files Browse the repository at this point in the history
…nstraint from indexed access" (#57202)
  • Loading branch information
Andarist authored Jan 29, 2024
1 parent 3c9aea3 commit 01527ce
Show file tree
Hide file tree
Showing 6 changed files with 336 additions and 113 deletions.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
90 changes: 49 additions & 41 deletions tests/baselines/reference/mappedTypeConstraints2.errors.txt
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
mappedTypeConstraints2.ts(10,11): error TS2322: Type 'Mapped2<K>[`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<K>[`get${string}`]' is not assignable to type '{ a: K; }'.
mappedTypeConstraints2.ts(16,11): error TS2322: Type 'Mapped3<K>[Uppercase<K>]' 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'.
mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not assignable to type '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'.
Type 'Mapped3<K>[Uppercase<string>]' is not assignable to type '{ a: K; }'.
Type 'Mapped3<K>[string]' is not assignable to type '{ a: K; }'.
mappedTypeConstraints2.ts(42,7): error TS2322: Type 'Mapped6<K>[keyof Mapped6<K>]' is not assignable to type '`_${string}`'.
Type 'Mapped6<K>[string] | Mapped6<K>[number] | Mapped6<K>[symbol]' is not assignable to type '`_${string}`'.
Type 'Mapped6<K>[string]' is not assignable to type '`_${string}`'.
mappedTypeConstraints2.ts(51,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}`]'.
mappedTypeConstraints2.ts(82,9): error TS2322: Type 'ObjectWithUnderscoredKeys<K>[`_${K}`]' is not assignable to type 'true'.
Type 'ObjectWithUnderscoredKeys<K>[`_${string}`]' is not assignable to type 'true'.


==== mappedTypeConstraints2.ts (3 errors) ====
==== mappedTypeConstraints2.ts (5 errors) ====
type Mapped1<K extends string> = { [P in K]: { a: P } };

function f1<K extends string>(obj: Mapped1<K>, key: K) {
Expand All @@ -35,12 +25,7 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not
const x: { a: K } = obj[key]; // Error
~
!!! error TS2322: Type 'Mapped2<K>[`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<K>[`get${string}`]' is not assignable to type '{ a: K; }'.
}

type Mapped3<K extends string> = { [P in K as Uppercase<P>]: { a: P } };
Expand All @@ -49,14 +34,38 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not
const x: { a: K } = obj[key]; // Error
~
!!! error TS2322: Type 'Mapped3<K>[Uppercase<K>]' 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'.
!!! 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; }'.
}

type Mapped4<K extends `_${string}`> = {
[P in K]: P;
};

function f4<K extends `_${string}`>(obj: Mapped4<K>, key: keyof Mapped4<K>) {
let s: `_${string}` = obj[key];
}

type Mapped5<K extends string> = {
[P in K as P extends `_${string}` ? P : never]: P;
};

function f5<K extends string>(obj: Mapped5<K>, key: keyof Mapped5<K>) {
let s: `_${string}` = obj[key];
}

// repro from #53066#issuecomment-1913384757

type Mapped6<K extends string> = {
[P in K as `_${P}`]: P;
};

function f6<K extends string>(obj: Mapped6<K>, key: keyof Mapped6<K>) {
let s: `_${string}` = obj[key]; // Error
~
!!! error TS2322: Type 'Mapped6<K>[keyof Mapped6<K>]' is not assignable to type '`_${string}`'.
!!! error TS2322: Type 'Mapped6<K>[string] | Mapped6<K>[number] | Mapped6<K>[symbol]' is not assignable to type '`_${string}`'.
!!! error TS2322: Type 'Mapped6<K>[string]' is not assignable to type '`_${string}`'.
}

// Repro from #47794
Expand All @@ -68,11 +77,7 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not
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: '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'.
!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo<T>[`get${T}`]'.

// Repro from #48626

Expand Down Expand Up @@ -103,6 +108,9 @@ mappedTypeConstraints2.ts(25,57): error TS2322: Type 'Foo<T>[`get${T}`]' is not
};

function genericTest<K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, key: K) {
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`];
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not
~~~~~~~~~~~~
!!! error TS2322: Type 'ObjectWithUnderscoredKeys<K>[`_${K}`]' is not assignable to type 'true'.
!!! error TS2322: Type 'ObjectWithUnderscoredKeys<K>[`_${string}`]' is not assignable to type 'true'.
}

51 changes: 49 additions & 2 deletions tests/baselines/reference/mappedTypeConstraints2.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,32 @@ function f3<K extends string>(obj: Mapped3<K>, key: Uppercase<K>) {
const x: { a: K } = obj[key]; // Error
}

type Mapped4<K extends `_${string}`> = {
[P in K]: P;
};

function f4<K extends `_${string}`>(obj: Mapped4<K>, key: keyof Mapped4<K>) {
let s: `_${string}` = obj[key];
}

type Mapped5<K extends string> = {
[P in K as P extends `_${string}` ? P : never]: P;
};

function f5<K extends string>(obj: Mapped5<K>, key: keyof Mapped5<K>) {
let s: `_${string}` = obj[key];
}

// repro from #53066#issuecomment-1913384757

type Mapped6<K extends string> = {
[P in K as `_${P}`]: P;
};

function f6<K extends string>(obj: Mapped6<K>, key: keyof Mapped6<K>) {
let s: `_${string}` = obj[key]; // Error
}

// Repro from #47794

type Foo<T extends string> = {
Expand Down Expand Up @@ -56,7 +82,7 @@ type ObjectWithUnderscoredKeys<K extends string> = {
};

function genericTest<K extends string>(objectWithUnderscoredKeys: ObjectWithUnderscoredKeys<K>, key: K) {
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`];
const shouldBeTrue: true = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not
}


Expand All @@ -71,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<T>[`get${T}`]' is not assignable to type 'T'
function validate(obj, bounds) {
for (const [key, val] of Object.entries(obj)) {
Expand All @@ -84,7 +119,7 @@ function validate(obj, bounds) {
return true;
}
function genericTest(objectWithUnderscoredKeys, key) {
const shouldBeTrue = objectWithUnderscoredKeys[`_${key}`];
const shouldBeTrue = objectWithUnderscoredKeys[`_${key}`]; // assignability fails here, but ideally should not
}


Expand All @@ -107,6 +142,18 @@ type Mapped3<K extends string> = {
};
};
declare function f3<K extends string>(obj: Mapped3<K>, key: Uppercase<K>): void;
type Mapped4<K extends `_${string}`> = {
[P in K]: P;
};
declare function f4<K extends `_${string}`>(obj: Mapped4<K>, key: keyof Mapped4<K>): void;
type Mapped5<K extends string> = {
[P in K as P extends `_${string}` ? P : never]: P;
};
declare function f5<K extends string>(obj: Mapped5<K>, key: keyof Mapped5<K>): void;
type Mapped6<K extends string> = {
[P in K as `_${P}`]: P;
};
declare function f6<K extends string>(obj: Mapped6<K>, key: keyof Mapped6<K>): void;
type Foo<T extends string> = {
[RemappedT in T as `get${RemappedT}`]: RemappedT;
};
Expand Down
Loading

0 comments on commit 01527ce

Please sign in to comment.