diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4405a31db2..1e16d2cbf0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7612,22 +7612,6 @@ namespace ts { return anyType; } - function getIndexedAccessForMappedType(type: MappedType, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) { - if (accessNode) { - // Check if the index type is assignable to 'keyof T' for the object type. - if (!isTypeAssignableTo(indexType, getIndexType(type))) { - error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(type)); - return unknownType; - } - if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && type.declaration.readonlyToken) { - error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(type)); - } - } - const mapper = createTypeMapper([getTypeParameterFromMappedType(type)], [indexType]); - const templateMapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper; - return instantiateType(getTemplateTypeFromMappedType(type), templateMapper); - } - function isGenericObjectType(type: Type): boolean { return type.flags & TypeFlags.TypeVariable ? true : getObjectFlags(type) & ObjectFlags.Mapped ? isGenericIndexType(getConstraintTypeFromMappedType(type)) : @@ -7653,12 +7637,14 @@ namespace ts { return false; } - // Given an indexed access type T[K], if T is an intersection containing one or more generic types and one or - // more object types with only a string index signature, e.g. '(U & V & { [x: string]: D })[K]', return a - // transformed type of the form '(U & V)[K] | D'. This allows us to properly reason about higher order indexed - // access types with default property values as expressed by D. + // Transform an indexed access to a simpler form, if possible. Return the simpler form, or return + // undefined if no transformation is possible. function getTransformedIndexedAccessType(type: IndexedAccessType): Type { const objectType = type.objectType; + // Given an indexed access type T[K], if T is an intersection containing one or more generic types and one or + // more object types with only a string index signature, e.g. '(U & V & { [x: string]: D })[K]', return a + // transformed type of the form '(U & V)[K] | D'. This allows us to properly reason about higher order indexed + // access types with default property values as expressed by D. if (objectType.flags & TypeFlags.Intersection && isGenericObjectType(objectType) && some((objectType).types, isStringIndexOnlyType)) { const regularTypes: Type[] = []; const stringIndexTypes: Type[] = []; @@ -7675,20 +7661,23 @@ namespace ts { getIntersectionType(stringIndexTypes) ]); } + // If the object type is a mapped type { [P in K]: E }, where K is generic, 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)) { + const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [type.indexType]); + const objectTypeMapper = (objectType).mapper; + const templateMapper = objectTypeMapper ? combineTypeMappers(objectTypeMapper, mapper) : mapper; + return instantiateType(getTemplateTypeFromMappedType(objectType), templateMapper); + } return undefined; } function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode): Type { - // If the object type is a mapped type { [P in K]: E }, where K is generic, 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)) { - return getIndexedAccessForMappedType(objectType, indexType, accessNode); - } - // Otherwise, if the index type is generic, or if the object type is generic and doesn't originate in an - // expression, we are performing a higher-order index access where we cannot meaningfully access the properties - // of the object type. Note that for a generic T and a non-generic K, we eagerly resolve T[K] if it originates - // in an expression. This is to preserve backwards compatibility. For example, an element access 'this["foo"]' + // If the index type is generic, or if the object type is generic and doesn't originate in an expression, + // we are performing a higher-order index access where we cannot meaningfully access the properties of the + // object type. Note that for a generic T and a non-generic K, we eagerly resolve T[K] if it originates in + // an expression. This is to preserve backwards compatibility. For example, an element access 'this["foo"]' // has always been resolved eagerly using the constraint type of 'this' at the given location. if (isGenericIndexType(indexType) || !(accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression) && isGenericObjectType(objectType)) { if (objectType.flags & TypeFlags.Any) { @@ -9310,7 +9299,7 @@ namespace ts { else if (target.flags & TypeFlags.IndexedAccess) { // A type S is related to a type T[K] if S is related to A[K], where K is string-like and // A is the apparent type of S. - const constraint = getConstraintOfType(target); + const constraint = getConstraintOfIndexedAccess(target); if (constraint) { if (result = isRelatedTo(source, constraint, reportErrors)) { errorInfo = saveErrorInfo; @@ -9350,7 +9339,7 @@ namespace ts { else if (source.flags & TypeFlags.IndexedAccess) { // A type S[K] is related to a type T if A[K] is related to T, where K is string-like and // A is the apparent type of S. - const constraint = getConstraintOfType(source); + const constraint = getConstraintOfIndexedAccess(source); if (constraint) { if (result = isRelatedTo(constraint, target, reportErrors)) { errorInfo = saveErrorInfo; @@ -18839,6 +18828,10 @@ namespace ts { const objectType = (type).objectType; const indexType = (type).indexType; if (isTypeAssignableTo(indexType, getIndexType(objectType))) { + if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && + getObjectFlags(objectType) & ObjectFlags.Mapped && (objectType).declaration.readonlyToken) { + error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); + } return type; } // Check if we're indexing with a numeric type and if either object or index types diff --git a/tests/baselines/reference/isomorphicMappedTypeInference.types b/tests/baselines/reference/isomorphicMappedTypeInference.types index c3414f4601..2e13f69c5e 100644 --- a/tests/baselines/reference/isomorphicMappedTypeInference.types +++ b/tests/baselines/reference/isomorphicMappedTypeInference.types @@ -69,7 +69,7 @@ function boxify(obj: T): Boxified { result[k] = box(obj[k]); >result[k] = box(obj[k]) : Box ->result[k] : Box +>result[k] : Boxified[keyof T] >result : Boxified >k : keyof T >box(obj[k]) : Box @@ -107,7 +107,7 @@ function unboxify(obj: Boxified): T { >k : keyof T >unbox(obj[k]) : T[keyof T] >unbox : (x: Box) => T ->obj[k] : Box +>obj[k] : Boxified[keyof T] >obj : Boxified >k : keyof T } @@ -131,7 +131,7 @@ function assignBoxified(obj: Boxified, values: T) { obj[k].value = values[k]; >obj[k].value = values[k] : T[keyof T] >obj[k].value : T[keyof T] ->obj[k] : Box +>obj[k] : Boxified[keyof T] >obj : Boxified >k : keyof T >value : T[keyof T] diff --git a/tests/baselines/reference/keyofAndForIn.types b/tests/baselines/reference/keyofAndForIn.types index d20f1a5707..c4997c05bf 100644 --- a/tests/baselines/reference/keyofAndForIn.types +++ b/tests/baselines/reference/keyofAndForIn.types @@ -27,8 +27,8 @@ function f1(obj: { [P in K]: T }, k: K) { >obj : { [P in K]: T; } let x1 = obj[k1]; ->x1 : T ->obj[k1] : T +>x1 : { [P in K]: T; }[K] +>obj[k1] : { [P in K]: T; }[K] >obj : { [P in K]: T; } >k1 : K } @@ -37,8 +37,8 @@ function f1(obj: { [P in K]: T }, k: K) { >obj : { [P in K]: T; } let x2 = obj[k2]; ->x2 : T ->obj[k2] : T +>x2 : { [P in K]: T; }[K] +>obj[k2] : { [P in K]: T; }[K] >obj : { [P in K]: T; } >k2 : K } @@ -70,8 +70,8 @@ function f2(obj: { [P in keyof T]: T[P] }, k: keyof T) { >obj : { [P in keyof T]: T[P]; } let x1 = obj[k1]; ->x1 : T[keyof T] ->obj[k1] : T[keyof T] +>x1 : { [P in keyof T]: T[P]; }[keyof T] +>obj[k1] : { [P in keyof T]: T[P]; }[keyof T] >obj : { [P in keyof T]: T[P]; } >k1 : keyof T } @@ -80,8 +80,8 @@ function f2(obj: { [P in keyof T]: T[P] }, k: keyof T) { >obj : { [P in keyof T]: T[P]; } let x2 = obj[k2]; ->x2 : T[keyof T] ->obj[k2] : T[keyof T] +>x2 : { [P in keyof T]: T[P]; }[keyof T] +>obj[k2] : { [P in keyof T]: T[P]; }[keyof T] >obj : { [P in keyof T]: T[P]; } >k2 : keyof T } @@ -115,8 +115,8 @@ function f3(obj: { [P in K]: T[P] }, k: K) { >obj : { [P in K]: T[P]; } let x1 = obj[k1]; ->x1 : T[K] ->obj[k1] : T[K] +>x1 : { [P in K]: T[P]; }[K] +>obj[k1] : { [P in K]: T[P]; }[K] >obj : { [P in K]: T[P]; } >k1 : K } @@ -125,8 +125,8 @@ function f3(obj: { [P in K]: T[P] }, k: K) { >obj : { [P in K]: T[P]; } let x2 = obj[k2]; ->x2 : T[K] ->obj[k2] : T[K] +>x2 : { [P in K]: T[P]; }[K] +>obj[k2] : { [P in K]: T[P]; }[K] >obj : { [P in K]: T[P]; } >k2 : K } diff --git a/tests/baselines/reference/keyofAndIndexedAccess.types b/tests/baselines/reference/keyofAndIndexedAccess.types index 671289527a..25d79e3f4f 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.types +++ b/tests/baselines/reference/keyofAndIndexedAccess.types @@ -2194,7 +2194,7 @@ class Form { this.childFormFactories[prop](value) >this.childFormFactories[prop](value) : Form ->this.childFormFactories[prop] : (v: T[K]) => Form +>this.childFormFactories[prop] : { [K in keyof T]: (v: T[K]) => Form; }[K] >this.childFormFactories : { [K in keyof T]: (v: T[K]) => Form; } >this : this >childFormFactories : { [K in keyof T]: (v: T[K]) => Form; } diff --git a/tests/baselines/reference/mappedTypeIndexedAccess.errors.txt b/tests/baselines/reference/mappedTypeIndexedAccess.errors.txt new file mode 100644 index 0000000000..24eae941c6 --- /dev/null +++ b/tests/baselines/reference/mappedTypeIndexedAccess.errors.txt @@ -0,0 +1,49 @@ +tests/cases/compiler/mappedTypeIndexedAccess.ts(18,5): error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; } | { key: "bar"; value: number; }'. + Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; }'. + Types of property 'value' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/compiler/mappedTypeIndexedAccess.ts(24,5): error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; } | { key: "bar"; value: number; }'. + Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; }'. + Types of property 'value' are incompatible. + Type 'number' is not assignable to type 'string'. + + +==== tests/cases/compiler/mappedTypeIndexedAccess.ts (2 errors) ==== + // Repro from #15756 + + type Pairs = { + [TKey in keyof T]: { + key: TKey; + value: T[TKey]; + }; + }; + + type Pair = Pairs[keyof T]; + + type FooBar = { + foo: string; + bar: number; + }; + + // Error expected here + let pair1: Pair = { + ~~~~~ +!!! error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; } | { key: "bar"; value: number; }'. +!!! error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; }'. +!!! error TS2322: Types of property 'value' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + key: "foo", + value: 3 + }; + + // Error expected here + let pair2: Pairs[keyof FooBar] = { + ~~~~~ +!!! error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; } | { key: "bar"; value: number; }'. +!!! error TS2322: Type '{ key: "foo"; value: number; }' is not assignable to type '{ key: "foo"; value: string; }'. +!!! error TS2322: Types of property 'value' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + key: "foo", + value: 3 + }; + \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeIndexedAccess.js b/tests/baselines/reference/mappedTypeIndexedAccess.js new file mode 100644 index 0000000000..60af082a6b --- /dev/null +++ b/tests/baselines/reference/mappedTypeIndexedAccess.js @@ -0,0 +1,43 @@ +//// [mappedTypeIndexedAccess.ts] +// Repro from #15756 + +type Pairs = { + [TKey in keyof T]: { + key: TKey; + value: T[TKey]; + }; +}; + +type Pair = Pairs[keyof T]; + +type FooBar = { + foo: string; + bar: number; +}; + +// Error expected here +let pair1: Pair = { + key: "foo", + value: 3 +}; + +// Error expected here +let pair2: Pairs[keyof FooBar] = { + key: "foo", + value: 3 +}; + + +//// [mappedTypeIndexedAccess.js] +"use strict"; +// Repro from #15756 +// Error expected here +var pair1 = { + key: "foo", + value: 3 +}; +// Error expected here +var pair2 = { + key: "foo", + value: 3 +}; diff --git a/tests/baselines/reference/mappedTypeRelationships.errors.txt b/tests/baselines/reference/mappedTypeRelationships.errors.txt index a1e1455b41..1ea0c5a261 100644 --- a/tests/baselines/reference/mappedTypeRelationships.errors.txt +++ b/tests/baselines/reference/mappedTypeRelationships.errors.txt @@ -26,17 +26,64 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(26,5): error TS2 Type 'T[string]' is not assignable to type 'U[string]'. Type 'T' is not assignable to type 'U'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(26,12): error TS2536: Type 'K' cannot be used to index type 'T'. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(30,5): error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'. - Type 'undefined' is not assignable to type 'T[keyof T]'. - Type 'undefined' is not assignable to type 'T[string]'. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(35,5): error TS2322: Type 'T[K] | undefined' is not assignable to type 'T[K]'. - Type 'undefined' is not assignable to type 'T[K]'. - Type 'undefined' is not assignable to type 'T[string]'. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(40,5): error TS2322: Type 'U[keyof T] | undefined' is not assignable to type 'T[keyof T]'. - Type 'undefined' is not assignable to type 'T[keyof T]'. - Type 'undefined' is not assignable to type 'T[string]'. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(41,5): error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T] | undefined'. - Type 'T[string]' is not assignable to type 'U[keyof T] | undefined'. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(30,5): error TS2322: Type 'Partial[keyof T]' is not assignable to type 'T[keyof T]'. + Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'. + Type 'undefined' is not assignable to type 'T[keyof T]'. + Type 'undefined' is not assignable to type 'T[string]'. + Type 'Partial[keyof T]' is not assignable to type 'T[string]'. + Type 'T[keyof T] | undefined' is not assignable to type 'T[string]'. + Type 'undefined' is not assignable to type 'T[string]'. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(35,5): error TS2322: Type 'Partial[K]' is not assignable to type 'T[K]'. + Type 'T[K] | undefined' is not assignable to type 'T[K]'. + Type 'undefined' is not assignable to type 'T[K]'. + Type 'undefined' is not assignable to type 'T[string]'. + Type 'Partial[K]' is not assignable to type 'T[string]'. + Type 'T[K] | undefined' is not assignable to type 'T[string]'. + Type 'undefined' is not assignable to type 'T[string]'. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(40,5): error TS2322: Type 'Partial[keyof T]' is not assignable to type 'T[keyof T]'. + Type 'U[keyof T] | undefined' is not assignable to type 'T[keyof T]'. + Type 'undefined' is not assignable to type 'T[keyof T]'. + Type 'undefined' is not assignable to type 'T[string]'. + Type 'Partial[keyof T]' is not assignable to type 'T[string]'. + Type 'U[keyof T] | undefined' is not assignable to type 'T[string]'. + Type 'undefined' is not assignable to type 'T[string]'. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(41,5): error TS2322: Type 'T[keyof T]' is not assignable to type 'Partial[keyof T]'. + Type 'T[string]' is not assignable to type 'Partial[keyof T]'. + Type 'T[string]' is not assignable to type 'U[keyof T] | undefined'. + Type 'T[string]' is not assignable to type 'U[keyof T]'. + Type 'T[keyof T]' is not assignable to type 'U[keyof T] | undefined'. + Type 'T[string]' is not assignable to type 'U[keyof T] | undefined'. + Type 'T[string]' is not assignable to type 'U[keyof T]'. + Type 'T[keyof T]' is not assignable to type 'U[keyof T]'. + Type 'T[string]' is not assignable to type 'U[keyof T]'. + Type 'T[string]' is not assignable to type 'U[string]'. + Type 'T[keyof T]' is not assignable to type 'U[string]'. + Type 'T[string]' is not assignable to type 'U[string]'. + Type 'T' is not assignable to type 'U'. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(45,5): error TS2322: Type 'Partial[K]' is not assignable to type 'T[K]'. + Type 'U[K] | undefined' is not assignable to type 'T[K]'. + Type 'undefined' is not assignable to type 'T[K]'. + Type 'undefined' is not assignable to type 'T[string]'. + Type 'Partial[K]' is not assignable to type 'T[string]'. + Type 'U[K] | undefined' is not assignable to type 'T[string]'. + Type 'undefined' is not assignable to type 'T[string]'. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(46,5): error TS2322: Type 'T[K]' is not assignable to type 'Partial[K]'. + Type 'T[string]' is not assignable to type 'Partial[K]'. + Type 'T[string]' is not assignable to type 'U[K] | undefined'. + Type 'T[string]' is not assignable to type 'U[K]'. + Type 'T[K]' is not assignable to type 'U[K] | undefined'. + Type 'T[string]' is not assignable to type 'U[K] | undefined'. + Type 'T[string]' is not assignable to type 'U[K]'. + Type 'T[K]' is not assignable to type 'U[K]'. + Type 'T[string]' is not assignable to type 'U[K]'. + Type 'T[string]' is not assignable to type 'U[string]'. + Type 'T[K]' is not assignable to type 'U[string]'. + Type 'T[string]' is not assignable to type 'U[string]'. + Type 'T' is not assignable to type 'U'. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(51,5): error TS2542: Index signature in type 'Readonly' only permits reading. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(56,5): error TS2542: Index signature in type 'Readonly' only permits reading. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(61,5): error TS2322: Type 'T[keyof T]' is not assignable to type 'Readonly[keyof T]'. + Type 'T[string]' is not assignable to type 'Readonly[keyof T]'. Type 'T[string]' is not assignable to type 'U[keyof T]'. Type 'T[keyof T]' is not assignable to type 'U[keyof T]'. Type 'T[string]' is not assignable to type 'U[keyof T]'. @@ -44,11 +91,9 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(41,5): error TS2 Type 'T[keyof T]' is not assignable to type 'U[string]'. Type 'T[string]' is not assignable to type 'U[string]'. Type 'T' is not assignable to type 'U'. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(45,5): error TS2322: Type 'U[K] | undefined' is not assignable to type 'T[K]'. - Type 'undefined' is not assignable to type 'T[K]'. - Type 'undefined' is not assignable to type 'T[string]'. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(46,5): error TS2322: Type 'T[K]' is not assignable to type 'U[K] | undefined'. - Type 'T[string]' is not assignable to type 'U[K] | undefined'. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(61,5): error TS2542: Index signature in type 'Readonly' only permits reading. +tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2322: Type 'T[K]' is not assignable to type 'Readonly[K]'. + Type 'T[string]' is not assignable to type 'Readonly[K]'. Type 'T[string]' is not assignable to type 'U[K]'. Type 'T[K]' is not assignable to type 'U[K]'. Type 'T[string]' is not assignable to type 'U[K]'. @@ -56,21 +101,6 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(46,5): error TS2 Type 'T[K]' is not assignable to type 'U[string]'. Type 'T[string]' is not assignable to type 'U[string]'. Type 'T' is not assignable to type 'U'. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(51,5): error TS2542: Index signature in type 'Readonly' only permits reading. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(56,5): error TS2542: Index signature in type 'Readonly' only permits reading. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(61,5): error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'. - Type 'T[string]' is not assignable to type 'U[keyof T]'. - Type 'T[string]' is not assignable to type 'U[string]'. - Type 'T[keyof T]' is not assignable to type 'U[string]'. - Type 'T[string]' is not assignable to type 'U[string]'. - Type 'T' is not assignable to type 'U'. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(61,5): error TS2542: Index signature in type 'Readonly' only permits reading. -tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2322: Type 'T[K]' is not assignable to type 'U[K]'. - Type 'T[string]' is not assignable to type 'U[K]'. - Type 'T[string]' is not assignable to type 'U[string]'. - Type 'T[K]' is not assignable to type 'U[string]'. - Type 'T[string]' is not assignable to type 'U[string]'. - Type 'T' is not assignable to type 'U'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2542: Index signature in type 'Readonly' only permits reading. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(72,5): error TS2322: Type 'Partial' is not assignable to type 'T'. tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(78,5): error TS2322: Type 'Partial' is not assignable to type 'Partial'. @@ -168,57 +198,81 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS function f10(x: T, y: Partial, k: keyof T) { x[k] = y[k]; // Error ~~~~ -!!! error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'. -!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'. -!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'Partial[keyof T]' is not assignable to type 'T[keyof T]'. +!!! error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'T[keyof T]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'Partial[keyof T]' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. y[k] = x[k]; } function f11(x: T, y: Partial, k: K) { x[k] = y[k]; // Error ~~~~ -!!! error TS2322: Type 'T[K] | undefined' is not assignable to type 'T[K]'. -!!! error TS2322: Type 'undefined' is not assignable to type 'T[K]'. -!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'Partial[K]' is not assignable to type 'T[K]'. +!!! error TS2322: Type 'T[K] | undefined' is not assignable to type 'T[K]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[K]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'Partial[K]' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'T[K] | undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. y[k] = x[k]; } function f12(x: T, y: Partial, k: keyof T) { x[k] = y[k]; // Error ~~~~ -!!! error TS2322: Type 'U[keyof T] | undefined' is not assignable to type 'T[keyof T]'. -!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'. -!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'Partial[keyof T]' is not assignable to type 'T[keyof T]'. +!!! error TS2322: Type 'U[keyof T] | undefined' is not assignable to type 'T[keyof T]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'Partial[keyof T]' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'U[keyof T] | undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. y[k] = x[k]; // Error ~~~~ -!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T] | undefined'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T] | undefined'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T]'. -!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T' is not assignable to type 'U'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'Partial[keyof T]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'Partial[keyof T]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T] | undefined'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T]'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T] | undefined'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T] | undefined'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T]'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. } function f13(x: T, y: Partial, k: K) { x[k] = y[k]; // Error ~~~~ -!!! error TS2322: Type 'U[K] | undefined' is not assignable to type 'T[K]'. -!!! error TS2322: Type 'undefined' is not assignable to type 'T[K]'. -!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'Partial[K]' is not assignable to type 'T[K]'. +!!! error TS2322: Type 'U[K] | undefined' is not assignable to type 'T[K]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[K]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'Partial[K]' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'U[K] | undefined' is not assignable to type 'T[string]'. +!!! error TS2322: Type 'undefined' is not assignable to type 'T[string]'. y[k] = x[k]; // Error ~~~~ -!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K] | undefined'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K] | undefined'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K]'. -!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T[K]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T' is not assignable to type 'U'. +!!! error TS2322: Type 'T[K]' is not assignable to type 'Partial[K]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'Partial[K]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K] | undefined'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K]'. +!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K] | undefined'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K] | undefined'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K]'. +!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[K]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. } function f20(x: T, y: Readonly, k: keyof T) { @@ -239,12 +293,15 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS x[k] = y[k]; y[k] = x[k]; // Error ~~~~ -!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T' is not assignable to type 'U'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'Readonly[keyof T]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'Readonly[keyof T]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T]'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[keyof T]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[keyof T]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. ~~~~ !!! error TS2542: Index signature in type 'Readonly' only permits reading. } @@ -253,12 +310,15 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS x[k] = y[k]; y[k] = x[k]; // Error ~~~~ -!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T[K]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. -!!! error TS2322: Type 'T' is not assignable to type 'U'. +!!! error TS2322: Type 'T[K]' is not assignable to type 'Readonly[K]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'Readonly[K]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K]'. +!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[K]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[K]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. ~~~~ !!! error TS2542: Index signature in type 'Readonly' only permits reading. } diff --git a/tests/baselines/reference/mappedTypes4.types b/tests/baselines/reference/mappedTypes4.types index 30e7eb2431..c003765d51 100644 --- a/tests/baselines/reference/mappedTypes4.types +++ b/tests/baselines/reference/mappedTypes4.types @@ -45,7 +45,7 @@ function boxify(obj: T): Boxified { result[k] = { value: obj[k] }; >result[k] = { value: obj[k] } : { value: T[keyof T]; } ->result[k] : Box +>result[k] : Boxified[keyof T] >result : Boxified >k : keyof T >{ value: obj[k] } : { value: T[keyof T]; } diff --git a/tests/baselines/reference/typeGuardsTypeParameters.types b/tests/baselines/reference/typeGuardsTypeParameters.types index 82a52a46b8..13fb996523 100644 --- a/tests/baselines/reference/typeGuardsTypeParameters.types +++ b/tests/baselines/reference/typeGuardsTypeParameters.types @@ -84,15 +84,15 @@ function fun(item: { [P in keyof T]: T[P] }) { >item : { [P in keyof T]: T[P]; } const value = item[key]; ->value : T[keyof T] ->item[key] : T[keyof T] +>value : { [P in keyof T]: T[P]; }[keyof T] +>item[key] : { [P in keyof T]: T[P]; }[keyof T] >item : { [P in keyof T]: T[P]; } >key : keyof T if (typeof value === "string") { >typeof value === "string" : boolean >typeof value : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" ->value : T[keyof T] +>value : { [P in keyof T]: T[P]; }[keyof T] >"string" : "string" strings.push(value); @@ -100,7 +100,7 @@ function fun(item: { [P in keyof T]: T[P] }) { >strings.push : (...items: string[]) => number >strings : string[] >push : (...items: string[]) => number ->value : T[keyof T] & string +>value : { [P in keyof T]: T[P]; }[keyof T] & string } } } diff --git a/tests/cases/compiler/mappedTypeIndexedAccess.ts b/tests/cases/compiler/mappedTypeIndexedAccess.ts new file mode 100644 index 0000000000..5be08a96f6 --- /dev/null +++ b/tests/cases/compiler/mappedTypeIndexedAccess.ts @@ -0,0 +1,29 @@ +// @strict: true + +// Repro from #15756 + +type Pairs = { + [TKey in keyof T]: { + key: TKey; + value: T[TKey]; + }; +}; + +type Pair = Pairs[keyof T]; + +type FooBar = { + foo: string; + bar: number; +}; + +// Error expected here +let pair1: Pair = { + key: "foo", + value: 3 +}; + +// Error expected here +let pair2: Pairs[keyof FooBar] = { + key: "foo", + value: 3 +};