Skip to content

Commit

Permalink
Merge pull request #31537 from microsoft/fixIndexedAccessConstraint
Browse files Browse the repository at this point in the history
Fix indexed access constraint
  • Loading branch information
ahejlsberg committed May 23, 2019
2 parents 6a559e3 + cd7a14a commit e601333
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/compiler/checker.ts
Expand Up @@ -7657,15 +7657,20 @@ namespace ts {
return hasNonCircularBaseConstraint(type) ? getConstraintFromIndexedAccess(type) : undefined;
}

function getSimplifiedTypeOrConstraint(type: Type) {
const simplified = getSimplifiedType(type, /*writing*/ false);
return simplified !== type ? simplified : getConstraintOfType(type);
}

function getConstraintFromIndexedAccess(type: IndexedAccessType) {
const indexConstraint = getConstraintOfType(type.indexType);
const indexConstraint = getSimplifiedTypeOrConstraint(type.indexType);
if (indexConstraint && indexConstraint !== type.indexType) {
const indexedAccess = getIndexedAccessTypeOrUndefined(type.objectType, indexConstraint);
if (indexedAccess) {
return indexedAccess;
}
}
const objectConstraint = getConstraintOfType(type.objectType);
const objectConstraint = getSimplifiedTypeOrConstraint(type.objectType);
if (objectConstraint && objectConstraint !== type.objectType) {
return getIndexedAccessTypeOrUndefined(objectConstraint, type.indexType);
}
Expand Down Expand Up @@ -13061,8 +13066,7 @@ namespace ts {
}
// A type S is assignable to keyof T if S is assignable to keyof C, where C is the
// simplified form of T or, if T doesn't simplify, the constraint of T.
const simplified = getSimplifiedType((<IndexType>target).type, /*writing*/ false);
const constraint = simplified !== (<IndexType>target).type ? simplified : getConstraintOfType((<IndexType>target).type);
const constraint = getSimplifiedTypeOrConstraint((<IndexType>target).type);
if (constraint) {
// We require Ternary.True here such that circular constraints don't cause
// false positives. For example, given 'T extends { [K in keyof T]: string }',
Expand Down
10 changes: 10 additions & 0 deletions tests/baselines/reference/keyofAndIndexedAccess2.errors.txt
Expand Up @@ -228,4 +228,14 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23
this["a"] = "b";
}
}

// Repro from #31385

type Foo<T> = { [key: string]: { [K in keyof T]: K }[keyof T] };

type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };

type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };

type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };

10 changes: 10 additions & 0 deletions tests/baselines/reference/keyofAndIndexedAccess2.js
Expand Up @@ -145,6 +145,16 @@ export class c {
this["a"] = "b";
}
}

// Repro from #31385

type Foo<T> = { [key: string]: { [K in keyof T]: K }[keyof T] };

type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };

type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };

type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };


//// [keyofAndIndexedAccess2.js]
Expand Down
44 changes: 44 additions & 0 deletions tests/baselines/reference/keyofAndIndexedAccess2.symbols
Expand Up @@ -517,3 +517,47 @@ export class c {
}
}

// Repro from #31385

type Foo<T> = { [key: string]: { [K in keyof T]: K }[keyof T] };
>Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 145, 1))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 149, 9))
>key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 149, 17))
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 149, 34))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 149, 9))
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 149, 34))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 149, 9))

type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };
>Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 149, 64))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 151, 9))
>key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 151, 17))
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 151, 34))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 151, 9))
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 151, 34))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 151, 9))

type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };
>Baz : Symbol(Baz, Decl(keyofAndIndexedAccess2.ts, 151, 66))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 153, 9))
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 153, 11))
>Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 145, 1))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 153, 9))
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 153, 35))
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 153, 11))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 153, 9))
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 153, 11))
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 153, 35))

type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };
>Qux : Symbol(Qux, Decl(keyofAndIndexedAccess2.ts, 153, 60))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 155, 9))
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 155, 11))
>Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 149, 64))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 155, 9))
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 155, 35))
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 155, 11))
>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 155, 9))
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 155, 11))
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 155, 35))

16 changes: 16 additions & 0 deletions tests/baselines/reference/keyofAndIndexedAccess2.types
Expand Up @@ -517,3 +517,19 @@ export class c {
}
}

// Repro from #31385

type Foo<T> = { [key: string]: { [K in keyof T]: K }[keyof T] };
>Foo : Foo<T>
>key : string

type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };
>Bar : Bar<T>
>key : string

type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };
>Baz : Baz<T, Q>

type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };
>Qux : Qux<T, Q>

10 changes: 10 additions & 0 deletions tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts
Expand Up @@ -147,3 +147,13 @@ export class c {
this["a"] = "b";
}
}

// Repro from #31385

type Foo<T> = { [key: string]: { [K in keyof T]: K }[keyof T] };

type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };

type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };

type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };

0 comments on commit e601333

Please sign in to comment.