diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fbca869e438..b85cdc340bb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9460,32 +9460,30 @@ namespace ts { } } } + else if (isGenericMappedType(target) && !isGenericMappedType(source) && getConstraintTypeFromMappedType(target) === getIndexType(source)) { + // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X. + const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target)); + const templateType = getTemplateTypeFromMappedType(target); + if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } if (source.flags & TypeFlags.TypeParameter) { - // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X. - if (getObjectFlags(target) & ObjectFlags.Mapped && getConstraintTypeFromMappedType(target) === getIndexType(source)) { - const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target)); - const templateType = getTemplateTypeFromMappedType(target); - if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { + let constraint = getConstraintOfTypeParameter(source); + // A type parameter with no constraint is not related to the non-primitive object type. + if (constraint || !(target.flags & TypeFlags.NonPrimitive)) { + if (!constraint || constraint.flags & TypeFlags.Any) { + constraint = emptyObjectType; + } + // Report constraint errors only if the constraint is not the empty object type + const reportConstraintErrors = reportErrors && constraint !== emptyObjectType; + if (result = isRelatedTo(constraint, target, reportConstraintErrors)) { errorInfo = saveErrorInfo; return result; } } - else { - let constraint = getConstraintOfTypeParameter(source); - // A type parameter with no constraint is not related to the non-primitive object type. - if (constraint || !(target.flags & TypeFlags.NonPrimitive)) { - if (!constraint || constraint.flags & TypeFlags.Any) { - constraint = emptyObjectType; - } - // Report constraint errors only if the constraint is not the empty object type - const reportConstraintErrors = reportErrors && constraint !== emptyObjectType; - if (result = isRelatedTo(constraint, target, reportConstraintErrors)) { - errorInfo = saveErrorInfo; - return result; - } - } - } } 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 diff --git a/tests/baselines/reference/mappedTypeRelationships.errors.txt b/tests/baselines/reference/mappedTypeRelationships.errors.txt index 1ea0c5a2612..2e51f73179d 100644 --- a/tests/baselines/reference/mappedTypeRelationships.errors.txt +++ b/tests/baselines/reference/mappedTypeRelationships.errors.txt @@ -460,4 +460,16 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS !!! error TS2322: Type 'T[string]' is not assignable to type 'U[string]'. !!! error TS2322: Type 'T' is not assignable to type 'U'. } + + function f80(t: T): Partial { + return t; + } + + function f81(t: T, k: K): Partial { + return t[k]; + } + + function f82(t: T, k1: K1, k2: K2): Partial { + return t[k1][k2]; + } \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeRelationships.js b/tests/baselines/reference/mappedTypeRelationships.js index 180c293b6c1..8bd44da5658 100644 --- a/tests/baselines/reference/mappedTypeRelationships.js +++ b/tests/baselines/reference/mappedTypeRelationships.js @@ -168,6 +168,18 @@ function f76(x: { [P in K]: T[P] }, y: { [P i x = y; y = x; // Error } + +function f80(t: T): Partial { + return t; +} + +function f81(t: T, k: K): Partial { + return t[k]; +} + +function f82(t: T, k1: K1, k2: K2): Partial { + return t[k1][k2]; +} //// [mappedTypeRelationships.js] @@ -289,6 +301,15 @@ function f76(x, y) { x = y; y = x; // Error } +function f80(t) { + return t; +} +function f81(t, k) { + return t[k]; +} +function f82(t, k1, k2) { + return t[k1][k2]; +} //// [mappedTypeRelationships.d.ts] @@ -369,3 +390,6 @@ declare function f76(x: { }, y: { [P in K]: U[P]; }): void; +declare function f80(t: T): Partial; +declare function f81(t: T, k: K): Partial; +declare function f82(t: T, k1: K1, k2: K2): Partial; diff --git a/tests/baselines/reference/mappedTypeRelationships.symbols b/tests/baselines/reference/mappedTypeRelationships.symbols index c398d9955ad..ed5317e3d75 100644 --- a/tests/baselines/reference/mappedTypeRelationships.symbols +++ b/tests/baselines/reference/mappedTypeRelationships.symbols @@ -750,3 +750,58 @@ function f76(x: { [P in K]: T[P] }, y: { [P i >x : Symbol(x, Decl(mappedTypeRelationships.ts, 165, 48)) } +function f80(t: T): Partial { +>f80 : Symbol(f80, Decl(mappedTypeRelationships.ts, 168, 1)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 170, 13)) +>t : Symbol(t, Decl(mappedTypeRelationships.ts, 170, 16)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 170, 13)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 170, 13)) + + return t; +>t : Symbol(t, Decl(mappedTypeRelationships.ts, 170, 16)) +} + +function f81(t: T, k: K): Partial { +>f81 : Symbol(f81, Decl(mappedTypeRelationships.ts, 172, 1)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 174, 13)) +>K : Symbol(K, Decl(mappedTypeRelationships.ts, 174, 15)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 174, 13)) +>t : Symbol(t, Decl(mappedTypeRelationships.ts, 174, 35)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 174, 13)) +>k : Symbol(k, Decl(mappedTypeRelationships.ts, 174, 40)) +>K : Symbol(K, Decl(mappedTypeRelationships.ts, 174, 15)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 174, 13)) +>K : Symbol(K, Decl(mappedTypeRelationships.ts, 174, 15)) + + return t[k]; +>t : Symbol(t, Decl(mappedTypeRelationships.ts, 174, 35)) +>k : Symbol(k, Decl(mappedTypeRelationships.ts, 174, 40)) +} + +function f82(t: T, k1: K1, k2: K2): Partial { +>f82 : Symbol(f82, Decl(mappedTypeRelationships.ts, 176, 1)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 178, 13)) +>K1 : Symbol(K1, Decl(mappedTypeRelationships.ts, 178, 15)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 178, 13)) +>K2 : Symbol(K2, Decl(mappedTypeRelationships.ts, 178, 35)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 178, 13)) +>K1 : Symbol(K1, Decl(mappedTypeRelationships.ts, 178, 15)) +>t : Symbol(t, Decl(mappedTypeRelationships.ts, 178, 60)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 178, 13)) +>k1 : Symbol(k1, Decl(mappedTypeRelationships.ts, 178, 65)) +>K1 : Symbol(K1, Decl(mappedTypeRelationships.ts, 178, 15)) +>k2 : Symbol(k2, Decl(mappedTypeRelationships.ts, 178, 73)) +>K2 : Symbol(K2, Decl(mappedTypeRelationships.ts, 178, 35)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypeRelationships.ts, 178, 13)) +>K1 : Symbol(K1, Decl(mappedTypeRelationships.ts, 178, 15)) +>K2 : Symbol(K2, Decl(mappedTypeRelationships.ts, 178, 35)) + + return t[k1][k2]; +>t : Symbol(t, Decl(mappedTypeRelationships.ts, 178, 60)) +>k1 : Symbol(k1, Decl(mappedTypeRelationships.ts, 178, 65)) +>k2 : Symbol(k2, Decl(mappedTypeRelationships.ts, 178, 73)) +} + diff --git a/tests/baselines/reference/mappedTypeRelationships.types b/tests/baselines/reference/mappedTypeRelationships.types index c698c6ba3c2..e1a00c9206b 100644 --- a/tests/baselines/reference/mappedTypeRelationships.types +++ b/tests/baselines/reference/mappedTypeRelationships.types @@ -856,3 +856,61 @@ function f76(x: { [P in K]: T[P] }, y: { [P i >x : { [P in K]: T[P]; } } +function f80(t: T): Partial { +>f80 : (t: T) => Partial +>T : T +>t : T +>T : T +>Partial : Partial +>T : T + + return t; +>t : T +} + +function f81(t: T, k: K): Partial { +>f81 : (t: T, k: K) => Partial +>T : T +>K : K +>T : T +>t : T +>T : T +>k : K +>K : K +>Partial : Partial +>T : T +>K : K + + return t[k]; +>t[k] : T[K] +>t : T +>k : K +} + +function f82(t: T, k1: K1, k2: K2): Partial { +>f82 : (t: T, k1: K1, k2: K2) => Partial +>T : T +>K1 : K1 +>T : T +>K2 : K2 +>T : T +>K1 : K1 +>t : T +>T : T +>k1 : K1 +>K1 : K1 +>k2 : K2 +>K2 : K2 +>Partial : Partial +>T : T +>K1 : K1 +>K2 : K2 + + return t[k1][k2]; +>t[k1][k2] : T[K1][K2] +>t[k1] : T[K1] +>t : T +>k1 : K1 +>k2 : K2 +} + diff --git a/tests/cases/conformance/types/mapped/mappedTypeRelationships.ts b/tests/cases/conformance/types/mapped/mappedTypeRelationships.ts index 7acacd6c1d7..9e8639bbb9e 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeRelationships.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeRelationships.ts @@ -170,3 +170,15 @@ function f76(x: { [P in K]: T[P] }, y: { [P i x = y; y = x; // Error } + +function f80(t: T): Partial { + return t; +} + +function f81(t: T, k: K): Partial { + return t[k]; +} + +function f82(t: T, k1: K1, k2: K2): Partial { + return t[k1][k2]; +}