diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c2f40c169dc3f..fc0e8f91e2097 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7594,8 +7594,8 @@ namespace ts { } // If the object type is a mapped type { [P in K]: E }, we instantiate E using a mapper that substitutes // the index type for P. For example, for an index access { [P in K]: Box }[X], we construct the - // type Box. - if (isGenericMappedType(objectType)) { + // type Box. Note: this substitution is applied only if K is not and indexing operation iself. + if (isGenericMappedType(objectType) && ((objectType).constraintType.flags & TypeFlags.IndexedAccess) === 0) { return getIndexedAccessForMappedType(objectType, indexType, accessNode); } // Otherwise we defer the operation by creating an indexed access type. @@ -18623,6 +18623,7 @@ namespace ts { } function checkIndexedAccessType(node: IndexedAccessTypeNode) { + checkSourceElement(node.objectType); checkIndexedAccessIndexType(getTypeFromIndexedAccessTypeNode(node), node); } diff --git a/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt b/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt index 1e88e2abc4341..0634c3419e014 100644 --- a/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt +++ b/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt @@ -15,6 +15,7 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(35,21): error tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(36,21): error TS2538: Type 'boolean' cannot be used as an index type. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(41,31): error TS2538: Type 'boolean' cannot be used as an index type. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(46,16): error TS2538: Type 'boolean' cannot be used as an index type. +tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(49,12): error TS1122: A tuple type element list cannot be empty. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(63,33): error TS2345: Argument of type '"size"' is not assignable to parameter of type '"name" | "width" | "height" | "visible"'. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(64,33): error TS2345: Argument of type '"name" | "size"' is not assignable to parameter of type '"name" | "width" | "height" | "visible"'. Type '"size"' is not assignable to type '"name" | "width" | "height" | "visible"'. @@ -28,7 +29,7 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(76,5): error tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(77,5): error TS2322: Type 'keyof (T & U)' is not assignable to type 'keyof (T | U)'. -==== tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts (24 errors) ==== +==== tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts (25 errors) ==== class Shape { name: string; width: number; @@ -112,6 +113,8 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(77,5): error type T60 = {}["toString"]; type T61 = []["toString"]; + ~~ +!!! error TS1122: A tuple type element list cannot be empty. declare let cond: boolean; diff --git a/tests/baselines/reference/mappedTypeErrors2.errors.txt b/tests/baselines/reference/mappedTypeErrors2.errors.txt new file mode 100644 index 0000000000000..f526b5b20a2f9 --- /dev/null +++ b/tests/baselines/reference/mappedTypeErrors2.errors.txt @@ -0,0 +1,36 @@ +tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(7,30): error TS2536: Type 'K' cannot be used to index type 'T1'. +tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(11,30): error TS2536: Type 'K' cannot be used to index type 'T3'. +tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(14,47): error TS2536: Type 'S' cannot be used to index type 'AB'. +tests/cases/conformance/types/mapped/mappedTypeErrors2.ts(17,49): error TS2536: Type 'L' cannot be used to index type '{}'. + + +==== tests/cases/conformance/types/mapped/mappedTypeErrors2.ts (4 errors) ==== + type AB = { + a: 'a' + b: 'a' + } + + type T1 = { [key in AB[K]]: true } + type T2 = T1[K] // BUG 1: should be error for K = 'b' + ~~~~~~~~ +!!! error TS2536: Type 'K' cannot be used to index type 'T1'. + + type R = AB[keyof AB]; // "a" + type T3 = { [key in R]: true } + type T4 = T3[K] // error as expected + ~~~~~ +!!! error TS2536: Type 'K' cannot be used to index type 'T3'. + + // BUG 2: 'extra' not checked in AB[S] + type T5 = {[key in AB[S]]: true}[S] + ~~~~~ +!!! error TS2536: Type 'S' cannot be used to index type 'AB'. + + // Should still error, for L = 'b' + type T6 = {[key in AB[S]]: true}[L] + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2536: Type 'L' cannot be used to index type '{}'. + + // Should be OK + type T7 = {[key in AB[S]]: true}[L] + \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeErrors2.js b/tests/baselines/reference/mappedTypeErrors2.js new file mode 100644 index 0000000000000..42a33d2ff3445 --- /dev/null +++ b/tests/baselines/reference/mappedTypeErrors2.js @@ -0,0 +1,49 @@ +//// [mappedTypeErrors2.ts] +type AB = { + a: 'a' + b: 'a' +} + +type T1 = { [key in AB[K]]: true } +type T2 = T1[K] // BUG 1: should be error for K = 'b' + +type R = AB[keyof AB]; // "a" +type T3 = { [key in R]: true } +type T4 = T3[K] // error as expected + +// BUG 2: 'extra' not checked in AB[S] +type T5 = {[key in AB[S]]: true}[S] + +// Should still error, for L = 'b' +type T6 = {[key in AB[S]]: true}[L] + +// Should be OK +type T7 = {[key in AB[S]]: true}[L] + + +//// [mappedTypeErrors2.js] + + +//// [mappedTypeErrors2.d.ts] +declare type AB = { + a: 'a'; + b: 'a'; +}; +declare type T1 = { + [key in AB[K]]: true; +}; +declare type T2 = T1[K]; +declare type R = AB[keyof AB]; +declare type T3 = { + [key in R]: true; +}; +declare type T4 = T3[K]; +declare type T5 = { + [key in AB[S]]: true; +}[S]; +declare type T6 = { + [key in AB[S]]: true; +}[L]; +declare type T7 = { + [key in AB[S]]: true; +}[L]; diff --git a/tests/cases/conformance/types/mapped/mappedTypeErrors2.ts b/tests/cases/conformance/types/mapped/mappedTypeErrors2.ts new file mode 100644 index 0000000000000..e02ec1a03a1ca --- /dev/null +++ b/tests/cases/conformance/types/mapped/mappedTypeErrors2.ts @@ -0,0 +1,23 @@ +// @strictNullChecks: true +// @declaration: true + +type AB = { + a: 'a' + b: 'a' +} + +type T1 = { [key in AB[K]]: true } +type T2 = T1[K] // BUG 1: should be error for K = 'b' + +type R = AB[keyof AB]; // "a" +type T3 = { [key in R]: true } +type T4 = T3[K] // error as expected + +// BUG 2: 'extra' not checked in AB[S] +type T5 = {[key in AB[S]]: true}[S] + +// Should still error, for L = 'b' +type T6 = {[key in AB[S]]: true}[L] + +// Should be OK +type T7 = {[key in AB[S]]: true}[L]