diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 197dc4ccbd58e..ad2da37c57990 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12012,13 +12012,15 @@ namespace ts { return Ternary.True; } // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X. - if (!isGenericMappedType(source) && getConstraintTypeFromMappedType(target) === getIndexType(source)) { + if (!isGenericMappedType(source) && isRelatedTo(getConstraintTypeFromMappedType(target), getIndexType(source))) { const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target)); const templateType = getTemplateTypeFromMappedType(target); if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { return result; } } + originalErrorInfo = errorInfo; + errorInfo = saveErrorInfo; } } diff --git a/tests/baselines/reference/homomorphicMappedTypeIntersectionAssignability.js b/tests/baselines/reference/homomorphicMappedTypeIntersectionAssignability.js new file mode 100644 index 0000000000000..80f0e8d1dbf88 --- /dev/null +++ b/tests/baselines/reference/homomorphicMappedTypeIntersectionAssignability.js @@ -0,0 +1,16 @@ +//// [homomorphicMappedTypeIntersectionAssignability.ts] +function f( + a: { weak?: string } & Readonly & { name: "ok" }, + b: Readonly, + c: Readonly & { name: string }) { + c = a; // Works + b = a; // Should also work +} + + +//// [homomorphicMappedTypeIntersectionAssignability.js] +"use strict"; +function f(a, b, c) { + c = a; // Works + b = a; // Should also work +} diff --git a/tests/baselines/reference/homomorphicMappedTypeIntersectionAssignability.symbols b/tests/baselines/reference/homomorphicMappedTypeIntersectionAssignability.symbols new file mode 100644 index 0000000000000..fae1f423be311 --- /dev/null +++ b/tests/baselines/reference/homomorphicMappedTypeIntersectionAssignability.symbols @@ -0,0 +1,33 @@ +=== tests/cases/compiler/homomorphicMappedTypeIntersectionAssignability.ts === +function f( +>f : Symbol(f, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 0, 0)) +>TType : Symbol(TType, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 0, 11)) + + a: { weak?: string } & Readonly & { name: "ok" }, +>a : Symbol(a, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 0, 18)) +>weak : Symbol(weak, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 1, 8)) +>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --)) +>TType : Symbol(TType, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 0, 11)) +>name : Symbol(name, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 1, 46)) + + b: Readonly, +>b : Symbol(b, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 1, 60)) +>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --)) +>TType : Symbol(TType, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 0, 11)) +>name : Symbol(name, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 2, 25)) + + c: Readonly & { name: string }) { +>c : Symbol(c, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 2, 42)) +>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --)) +>TType : Symbol(TType, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 0, 11)) +>name : Symbol(name, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 3, 26)) + + c = a; // Works +>c : Symbol(c, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 2, 42)) +>a : Symbol(a, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 0, 18)) + + b = a; // Should also work +>b : Symbol(b, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 1, 60)) +>a : Symbol(a, Decl(homomorphicMappedTypeIntersectionAssignability.ts, 0, 18)) +} + diff --git a/tests/baselines/reference/homomorphicMappedTypeIntersectionAssignability.types b/tests/baselines/reference/homomorphicMappedTypeIntersectionAssignability.types new file mode 100644 index 0000000000000..eafa5586fb13d --- /dev/null +++ b/tests/baselines/reference/homomorphicMappedTypeIntersectionAssignability.types @@ -0,0 +1,28 @@ +=== tests/cases/compiler/homomorphicMappedTypeIntersectionAssignability.ts === +function f( +>f : (a: { weak?: string | undefined; } & Readonly & { name: "ok"; }, b: Readonly, c: Readonly & { name: string; }) => void + + a: { weak?: string } & Readonly & { name: "ok" }, +>a : { weak?: string | undefined; } & Readonly & { name: "ok"; } +>weak : string | undefined +>name : "ok" + + b: Readonly, +>b : Readonly +>name : string + + c: Readonly & { name: string }) { +>c : Readonly & { name: string; } +>name : string + + c = a; // Works +>c = a : { weak?: string | undefined; } & Readonly & { name: "ok"; } +>c : Readonly & { name: string; } +>a : { weak?: string | undefined; } & Readonly & { name: "ok"; } + + b = a; // Should also work +>b = a : { weak?: string | undefined; } & Readonly & { name: "ok"; } +>b : Readonly +>a : { weak?: string | undefined; } & Readonly & { name: "ok"; } +} + diff --git a/tests/baselines/reference/reactReadonlyHOCAssignabilityReal.js b/tests/baselines/reference/reactReadonlyHOCAssignabilityReal.js new file mode 100644 index 0000000000000..57f6680e098f7 --- /dev/null +++ b/tests/baselines/reference/reactReadonlyHOCAssignabilityReal.js @@ -0,0 +1,53 @@ +//// [reactReadonlyHOCAssignabilityReal.tsx] +/// +import * as React from "react"; + +function myHigherOrderComponent

(Inner: React.ComponentClass

): React.ComponentClass

{ + return class OuterComponent extends React.Component

{ + render() { + return ; + } + }; +} + +//// [reactReadonlyHOCAssignabilityReal.js] +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +exports.__esModule = true; +/// +var React = require("react"); +function myHigherOrderComponent(Inner) { + return /** @class */ (function (_super) { + __extends(OuterComponent, _super); + function OuterComponent() { + return _super !== null && _super.apply(this, arguments) || this; + } + OuterComponent.prototype.render = function () { + return React.createElement(Inner, __assign({}, this.props, { name: "Matt" })); + }; + return OuterComponent; + }(React.Component)); +} diff --git a/tests/baselines/reference/reactReadonlyHOCAssignabilityReal.symbols b/tests/baselines/reference/reactReadonlyHOCAssignabilityReal.symbols new file mode 100644 index 0000000000000..c0fc1dbafd0a9 --- /dev/null +++ b/tests/baselines/reference/reactReadonlyHOCAssignabilityReal.symbols @@ -0,0 +1,36 @@ +=== tests/cases/compiler/reactReadonlyHOCAssignabilityReal.tsx === +/// +import * as React from "react"; +>React : Symbol(React, Decl(reactReadonlyHOCAssignabilityReal.tsx, 1, 6)) + +function myHigherOrderComponent

(Inner: React.ComponentClass

): React.ComponentClass

{ +>myHigherOrderComponent : Symbol(myHigherOrderComponent, Decl(reactReadonlyHOCAssignabilityReal.tsx, 1, 31)) +>P : Symbol(P, Decl(reactReadonlyHOCAssignabilityReal.tsx, 3, 32)) +>Inner : Symbol(Inner, Decl(reactReadonlyHOCAssignabilityReal.tsx, 3, 35)) +>React : Symbol(React, Decl(reactReadonlyHOCAssignabilityReal.tsx, 1, 6)) +>ComponentClass : Symbol(React.ComponentClass, Decl(react16.d.ts, 421, 9)) +>P : Symbol(P, Decl(reactReadonlyHOCAssignabilityReal.tsx, 3, 32)) +>name : Symbol(name, Decl(reactReadonlyHOCAssignabilityReal.tsx, 3, 68)) +>React : Symbol(React, Decl(reactReadonlyHOCAssignabilityReal.tsx, 1, 6)) +>ComponentClass : Symbol(React.ComponentClass, Decl(react16.d.ts, 421, 9)) +>P : Symbol(P, Decl(reactReadonlyHOCAssignabilityReal.tsx, 3, 32)) + + return class OuterComponent extends React.Component

{ +>OuterComponent : Symbol(OuterComponent, Decl(reactReadonlyHOCAssignabilityReal.tsx, 4, 10)) +>React.Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94)) +>React : Symbol(React, Decl(reactReadonlyHOCAssignabilityReal.tsx, 1, 6)) +>Component : Symbol(React.Component, Decl(react16.d.ts, 345, 54), Decl(react16.d.ts, 349, 94)) +>P : Symbol(P, Decl(reactReadonlyHOCAssignabilityReal.tsx, 3, 32)) + + render() { +>render : Symbol(OuterComponent.render, Decl(reactReadonlyHOCAssignabilityReal.tsx, 4, 60)) + + return ; +>Inner : Symbol(Inner, Decl(reactReadonlyHOCAssignabilityReal.tsx, 3, 35)) +>this.props : Symbol(React.Component.props, Decl(react16.d.ts, 367, 32)) +>this : Symbol(OuterComponent, Decl(reactReadonlyHOCAssignabilityReal.tsx, 4, 10)) +>props : Symbol(React.Component.props, Decl(react16.d.ts, 367, 32)) +>name : Symbol(name, Decl(reactReadonlyHOCAssignabilityReal.tsx, 6, 41)) + } + }; +} diff --git a/tests/baselines/reference/reactReadonlyHOCAssignabilityReal.types b/tests/baselines/reference/reactReadonlyHOCAssignabilityReal.types new file mode 100644 index 0000000000000..1f67ab5adf936 --- /dev/null +++ b/tests/baselines/reference/reactReadonlyHOCAssignabilityReal.types @@ -0,0 +1,32 @@ +=== tests/cases/compiler/reactReadonlyHOCAssignabilityReal.tsx === +/// +import * as React from "react"; +>React : typeof React + +function myHigherOrderComponent

(Inner: React.ComponentClass

): React.ComponentClass

{ +>myHigherOrderComponent :

(Inner: React.ComponentClass

) => React.ComponentClass +>Inner : React.ComponentClass

+>React : any +>name : string +>React : any + + return class OuterComponent extends React.Component

{ +>class OuterComponent extends React.Component

{ render() { return ; } } : typeof OuterComponent +>OuterComponent : typeof OuterComponent +>React.Component : React.Component +>React : typeof React +>Component : typeof React.Component + + render() { +>render : () => JSX.Element + + return ; +> : JSX.Element +>Inner : React.ComponentClass

+>this.props : Readonly<{ children?: React.ReactNode; }> & Readonly

+>this : this +>props : Readonly<{ children?: React.ReactNode; }> & Readonly

+>name : "Matt" + } + }; +} diff --git a/tests/cases/compiler/homomorphicMappedTypeIntersectionAssignability.ts b/tests/cases/compiler/homomorphicMappedTypeIntersectionAssignability.ts new file mode 100644 index 0000000000000..f4f452e115634 --- /dev/null +++ b/tests/cases/compiler/homomorphicMappedTypeIntersectionAssignability.ts @@ -0,0 +1,8 @@ +// @strict: true +function f( + a: { weak?: string } & Readonly & { name: "ok" }, + b: Readonly, + c: Readonly & { name: string }) { + c = a; // Works + b = a; // Should also work +} diff --git a/tests/cases/compiler/reactReadonlyHOCAssignabilityReal.tsx b/tests/cases/compiler/reactReadonlyHOCAssignabilityReal.tsx new file mode 100644 index 0000000000000..c573f699beb2f --- /dev/null +++ b/tests/cases/compiler/reactReadonlyHOCAssignabilityReal.tsx @@ -0,0 +1,12 @@ +// @strict: true +// @jsx: react +/// +import * as React from "react"; + +function myHigherOrderComponent

(Inner: React.ComponentClass

): React.ComponentClass

{ + return class OuterComponent extends React.Component

{ + render() { + return ; + } + }; +} \ No newline at end of file