Skip to content

Commit 327bc3c

Browse files
authored
Merge pull request #32071 from andrewbranch/bug/31070
Allow assignability of non-empty object to generic mapped type
2 parents c91e147 + 27b8c45 commit 327bc3c

8 files changed

+261
-120
lines changed

src/compiler/checker.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -13212,14 +13212,14 @@ namespace ts {
1321213212
if (!isGenericMappedType(source)) {
1321313213
const targetConstraint = getConstraintTypeFromMappedType(target);
1321413214
const sourceKeys = getIndexType(source, /*stringsOnly*/ undefined, /*noIndexSignatures*/ true);
13215-
const hasOptionalUnionKeys = modifiers & MappedTypeModifiers.IncludeOptional && targetConstraint.flags & TypeFlags.Union;
13216-
const filteredByApplicability = hasOptionalUnionKeys ? filterType(targetConstraint, t => !!isRelatedTo(t, sourceKeys)) : undefined;
13215+
const includeOptional = modifiers & MappedTypeModifiers.IncludeOptional;
13216+
const filteredByApplicability = includeOptional ? intersectTypes(targetConstraint, sourceKeys) : undefined;
1321713217
// A source type T is related to a target type { [P in Q]: X } if Q is related to keyof T and T[Q] is related to X.
1321813218
// A source type T is related to a target type { [P in Q]?: X } if some constituent Q' of Q is related to keyof T and T[Q'] is related to X.
13219-
if (hasOptionalUnionKeys
13219+
if (includeOptional
1322013220
? !(filteredByApplicability!.flags & TypeFlags.Never)
1322113221
: isRelatedTo(targetConstraint, sourceKeys)) {
13222-
const indexingType = hasOptionalUnionKeys ? filteredByApplicability! : getTypeParameterFromMappedType(target);
13222+
const indexingType = filteredByApplicability || getTypeParameterFromMappedType(target);
1322313223
const indexedAccessType = getIndexedAccessType(source, indexingType);
1322413224
const templateType = getTemplateTypeFromMappedType(target);
1322513225
if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) {

tests/baselines/reference/circularlyConstrainedMappedTypeContainingConditionalNoInfiniteInstantiationDepth.errors.txt

+98-58
Large diffs are not rendered by default.

tests/baselines/reference/mappedTypeRelationships.errors.txt

+6
Original file line numberDiff line numberDiff line change
@@ -386,4 +386,10 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS
386386
function f82<T, K1 extends keyof T, K2 extends keyof T[K1]>(t: T, k1: K1, k2: K2): Partial<T[K1][K2]> {
387387
return t[k1][k2];
388388
}
389+
390+
// #31070
391+
type Numeric<T> = { [K in keyof T]?: number };
392+
function f90<T extends { x: number }>() {
393+
const n: Numeric<T> = { x: 1 };
394+
}
389395

tests/baselines/reference/mappedTypeRelationships.js

+15
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ function f81<T, K extends keyof T>(t: T, k: K): Partial<T[K]> {
180180
function f82<T, K1 extends keyof T, K2 extends keyof T[K1]>(t: T, k1: K1, k2: K2): Partial<T[K1][K2]> {
181181
return t[k1][k2];
182182
}
183+
184+
// #31070
185+
type Numeric<T> = { [K in keyof T]?: number };
186+
function f90<T extends { x: number }>() {
187+
const n: Numeric<T> = { x: 1 };
188+
}
183189

184190

185191
//// [mappedTypeRelationships.js]
@@ -310,6 +316,9 @@ function f81(t, k) {
310316
function f82(t, k1, k2) {
311317
return t[k1][k2];
312318
}
319+
function f90() {
320+
var n = { x: 1 };
321+
}
313322

314323

315324
//// [mappedTypeRelationships.d.ts]
@@ -393,3 +402,9 @@ declare function f76<T, U extends T, K extends keyof T>(x: {
393402
declare function f80<T>(t: T): Partial<T>;
394403
declare function f81<T, K extends keyof T>(t: T, k: K): Partial<T[K]>;
395404
declare function f82<T, K1 extends keyof T, K2 extends keyof T[K1]>(t: T, k1: K1, k2: K2): Partial<T[K1][K2]>;
405+
declare type Numeric<T> = {
406+
[K in keyof T]?: number;
407+
};
408+
declare function f90<T extends {
409+
x: number;
410+
}>(): void;

tests/baselines/reference/mappedTypeRelationships.symbols

+19
Original file line numberDiff line numberDiff line change
@@ -805,3 +805,22 @@ function f82<T, K1 extends keyof T, K2 extends keyof T[K1]>(t: T, k1: K1, k2: K2
805805
>k2 : Symbol(k2, Decl(mappedTypeRelationships.ts, 178, 73))
806806
}
807807

808+
// #31070
809+
type Numeric<T> = { [K in keyof T]?: number };
810+
>Numeric : Symbol(Numeric, Decl(mappedTypeRelationships.ts, 180, 1))
811+
>T : Symbol(T, Decl(mappedTypeRelationships.ts, 183, 13))
812+
>K : Symbol(K, Decl(mappedTypeRelationships.ts, 183, 21))
813+
>T : Symbol(T, Decl(mappedTypeRelationships.ts, 183, 13))
814+
815+
function f90<T extends { x: number }>() {
816+
>f90 : Symbol(f90, Decl(mappedTypeRelationships.ts, 183, 46))
817+
>T : Symbol(T, Decl(mappedTypeRelationships.ts, 184, 13))
818+
>x : Symbol(x, Decl(mappedTypeRelationships.ts, 184, 24))
819+
820+
const n: Numeric<T> = { x: 1 };
821+
>n : Symbol(n, Decl(mappedTypeRelationships.ts, 185, 9))
822+
>Numeric : Symbol(Numeric, Decl(mappedTypeRelationships.ts, 180, 1))
823+
>T : Symbol(T, Decl(mappedTypeRelationships.ts, 184, 13))
824+
>x : Symbol(x, Decl(mappedTypeRelationships.ts, 185, 27))
825+
}
826+

tests/baselines/reference/mappedTypeRelationships.types

+15
Original file line numberDiff line numberDiff line change
@@ -653,3 +653,18 @@ function f82<T, K1 extends keyof T, K2 extends keyof T[K1]>(t: T, k1: K1, k2: K2
653653
>k2 : K2
654654
}
655655

656+
// #31070
657+
type Numeric<T> = { [K in keyof T]?: number };
658+
>Numeric : Numeric<T>
659+
660+
function f90<T extends { x: number }>() {
661+
>f90 : <T extends { x: number; }>() => void
662+
>x : number
663+
664+
const n: Numeric<T> = { x: 1 };
665+
>n : Numeric<T>
666+
>{ x: 1 } : { x: number; }
667+
>x : number
668+
>1 : 1
669+
}
670+

0 commit comments

Comments
 (0)