Skip to content

Commit 5cdce29

Browse files
committed
Make T assignable to Readonly<U> if T is assignable to U, not just if
T = U. Fixes #27484.
1 parent 85a3475 commit 5cdce29

File tree

6 files changed

+73
-2
lines changed

6 files changed

+73
-2
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11904,9 +11904,11 @@ namespace ts {
1190411904
const template = getTemplateTypeFromMappedType(target);
1190511905
const modifiers = getMappedTypeModifiers(target);
1190611906
if (!(modifiers & MappedTypeModifiers.ExcludeOptional)) {
11907-
if (template.flags & TypeFlags.IndexedAccess && (<IndexedAccessType>template).objectType === source &&
11907+
if (template.flags & TypeFlags.IndexedAccess &&
1190811908
(<IndexedAccessType>template).indexType === getTypeParameterFromMappedType(target)) {
11909-
return Ternary.True;
11909+
if (result = isRelatedTo(source, (<IndexedAccessType>template).objectType)) {
11910+
return result;
11911+
}
1191011912
}
1191111913
// A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X.
1191211914
if (!isGenericMappedType(source) && getConstraintTypeFromMappedType(target) === getIndexType(source)) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
tests/cases/compiler/genericMappedTypeIntersections.ts(3,52): error TS2339: Property 'assign' does not exist on type 'ObjectConstructor'.
2+
3+
4+
==== tests/cases/compiler/genericMappedTypeIntersections.ts (1 errors) ====
5+
// Repro for #27484
6+
function foo<P>(props: Readonly<{children?: string}> & Readonly<P>) {
7+
let x: Readonly<P & { name: string }> = Object.assign({}, props, {name: "Matt"});
8+
~~~~~~
9+
!!! error TS2339: Property 'assign' does not exist on type 'ObjectConstructor'.
10+
}
11+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//// [genericMappedTypeIntersections.ts]
2+
// Repro for #27484
3+
function foo<P>(props: Readonly<{children?: string}> & Readonly<P>) {
4+
let x: Readonly<P & { name: string }> = Object.assign({}, props, {name: "Matt"});
5+
}
6+
7+
8+
//// [genericMappedTypeIntersections.js]
9+
// Repro for #27484
10+
function foo(props) {
11+
var x = Object.assign({}, props, { name: "Matt" });
12+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/compiler/genericMappedTypeIntersections.ts ===
2+
// Repro for #27484
3+
function foo<P>(props: Readonly<{children?: string}> & Readonly<P>) {
4+
>foo : Symbol(foo, Decl(genericMappedTypeIntersections.ts, 0, 0))
5+
>P : Symbol(P, Decl(genericMappedTypeIntersections.ts, 1, 13))
6+
>props : Symbol(props, Decl(genericMappedTypeIntersections.ts, 1, 16))
7+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
8+
>children : Symbol(children, Decl(genericMappedTypeIntersections.ts, 1, 33))
9+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
10+
>P : Symbol(P, Decl(genericMappedTypeIntersections.ts, 1, 13))
11+
12+
let x: Readonly<P & { name: string }> = Object.assign({}, props, {name: "Matt"});
13+
>x : Symbol(x, Decl(genericMappedTypeIntersections.ts, 2, 7))
14+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
15+
>P : Symbol(P, Decl(genericMappedTypeIntersections.ts, 1, 13))
16+
>name : Symbol(name, Decl(genericMappedTypeIntersections.ts, 2, 25))
17+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
18+
>props : Symbol(props, Decl(genericMappedTypeIntersections.ts, 1, 16))
19+
>name : Symbol(name, Decl(genericMappedTypeIntersections.ts, 2, 70))
20+
}
21+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/compiler/genericMappedTypeIntersections.ts ===
2+
// Repro for #27484
3+
function foo<P>(props: Readonly<{children?: string}> & Readonly<P>) {
4+
>foo : <P>(props: Readonly<{ children?: string; }> & Readonly<P>) => void
5+
>props : Readonly<{ children?: string; }> & Readonly<P>
6+
>children : string
7+
8+
let x: Readonly<P & { name: string }> = Object.assign({}, props, {name: "Matt"});
9+
>x : Readonly<P & { name: string; }>
10+
>name : string
11+
>Object.assign({}, props, {name: "Matt"}) : any
12+
>Object.assign : any
13+
>Object : ObjectConstructor
14+
>assign : any
15+
>{} : {}
16+
>props : Readonly<{ children?: string; }> & Readonly<P>
17+
>{name: "Matt"} : { name: string; }
18+
>name : string
19+
>"Matt" : "Matt"
20+
}
21+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Repro for #27484
2+
function foo<P>(props: Readonly<{children?: string}> & Readonly<P>) {
3+
let x: Readonly<P & { name: string }> = Object.assign({}, props, {name: "Matt"});
4+
}

0 commit comments

Comments
 (0)