From c3e0413375445b9410725de9c953debec3a711d6 Mon Sep 17 00:00:00 2001 From: amaksimovich Date: Wed, 13 Mar 2019 19:35:16 +0300 Subject: [PATCH] Add more information in case of incompatible constructor signature #21253 --- src/compiler/checker.ts | 8 ++++++++ src/compiler/diagnosticMessages.json | 4 ++++ .../assigningIncompatibleConstructor.errors.txt | 13 +++++++++++++ .../reference/assigningIncompatibleConstructor.js | 12 ++++++++++++ .../assigningIncompatibleConstructor.symbols | 10 ++++++++++ .../assigningIncompatibleConstructor.types | 9 +++++++++ .../compiler/assigningIncompatibleConstructor.ts | 2 ++ 7 files changed, 58 insertions(+) create mode 100644 tests/baselines/reference/assigningIncompatibleConstructor.errors.txt create mode 100644 tests/baselines/reference/assigningIncompatibleConstructor.js create mode 100644 tests/baselines/reference/assigningIncompatibleConstructor.symbols create mode 100644 tests/baselines/reference/assigningIncompatibleConstructor.types create mode 100644 tests/cases/compiler/assigningIncompatibleConstructor.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 898ebbfbcd6ad..c7d2f59cf1751 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13232,6 +13232,14 @@ namespace ts { // to the quadratic nature of the logic below. const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks; result = signatureRelatedTo(sourceSignatures[0], targetSignatures[0], eraseGenerics, reportErrors); + if (result === Ternary.False && reportErrors && targetSignatures[0].declaration && isConstructSignatureDeclaration(targetSignatures[0].declaration) + && getObjectFlags(source) & getObjectFlags(target)) { + const flags = TypeFormatFlags.WriteArrowStyleSignature; + const sourceSignature = signatureToString(sourceSignatures[0], /*enclosingDeclaration*/ undefined, flags, kind); + const targetSignature = signatureToString(targetSignatures[0], /*enclosingDeclaration*/ undefined, flags, kind); + reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, sourceSignature, targetSignature); + reportError(Diagnostics.Types_of_constructor_signature_are_incompatible); + } } else { outer: for (const t of targetSignatures) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 5ef209b0a88da..1ba64c44dedd4 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2601,6 +2601,10 @@ "category": "Error", "code": 2753 }, + "Types of constructor signature are incompatible.": { + "category": "Error", + "code": 2754 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/assigningIncompatibleConstructor.errors.txt b/tests/baselines/reference/assigningIncompatibleConstructor.errors.txt new file mode 100644 index 0000000000000..e510bb1bf26cb --- /dev/null +++ b/tests/baselines/reference/assigningIncompatibleConstructor.errors.txt @@ -0,0 +1,13 @@ +tests/cases/compiler/assigningIncompatibleConstructor.ts(2,5): error TS2322: Type 'typeof Foo' is not assignable to type 'new () => Foo'. + Types of constructor signature are incompatible. + Type 'new (a: string) => Foo' is not assignable to type 'new () => Foo'. + + +==== tests/cases/compiler/assigningIncompatibleConstructor.ts (1 errors) ==== + class Foo { constructor(a: string) { } } + let FooConstructor: { new(): Foo } = Foo; + ~~~~~~~~~~~~~~ +!!! error TS2322: Type 'typeof Foo' is not assignable to type 'new () => Foo'. +!!! error TS2322: Types of constructor signature are incompatible. +!!! error TS2322: Type 'new (a: string) => Foo' is not assignable to type 'new () => Foo'. + \ No newline at end of file diff --git a/tests/baselines/reference/assigningIncompatibleConstructor.js b/tests/baselines/reference/assigningIncompatibleConstructor.js new file mode 100644 index 0000000000000..47370fa7c55bd --- /dev/null +++ b/tests/baselines/reference/assigningIncompatibleConstructor.js @@ -0,0 +1,12 @@ +//// [assigningIncompatibleConstructor.ts] +class Foo { constructor(a: string) { } } +let FooConstructor: { new(): Foo } = Foo; + + +//// [assigningIncompatibleConstructor.js] +var Foo = /** @class */ (function () { + function Foo(a) { + } + return Foo; +}()); +var FooConstructor = Foo; diff --git a/tests/baselines/reference/assigningIncompatibleConstructor.symbols b/tests/baselines/reference/assigningIncompatibleConstructor.symbols new file mode 100644 index 0000000000000..fd4554026bafa --- /dev/null +++ b/tests/baselines/reference/assigningIncompatibleConstructor.symbols @@ -0,0 +1,10 @@ +=== tests/cases/compiler/assigningIncompatibleConstructor.ts === +class Foo { constructor(a: string) { } } +>Foo : Symbol(Foo, Decl(assigningIncompatibleConstructor.ts, 0, 0)) +>a : Symbol(a, Decl(assigningIncompatibleConstructor.ts, 0, 24)) + +let FooConstructor: { new(): Foo } = Foo; +>FooConstructor : Symbol(FooConstructor, Decl(assigningIncompatibleConstructor.ts, 1, 3)) +>Foo : Symbol(Foo, Decl(assigningIncompatibleConstructor.ts, 0, 0)) +>Foo : Symbol(Foo, Decl(assigningIncompatibleConstructor.ts, 0, 0)) + diff --git a/tests/baselines/reference/assigningIncompatibleConstructor.types b/tests/baselines/reference/assigningIncompatibleConstructor.types new file mode 100644 index 0000000000000..1583814f2bf6e --- /dev/null +++ b/tests/baselines/reference/assigningIncompatibleConstructor.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/assigningIncompatibleConstructor.ts === +class Foo { constructor(a: string) { } } +>Foo : Foo +>a : string + +let FooConstructor: { new(): Foo } = Foo; +>FooConstructor : new () => Foo +>Foo : typeof Foo + diff --git a/tests/cases/compiler/assigningIncompatibleConstructor.ts b/tests/cases/compiler/assigningIncompatibleConstructor.ts new file mode 100644 index 0000000000000..50acc4c6d8c82 --- /dev/null +++ b/tests/cases/compiler/assigningIncompatibleConstructor.ts @@ -0,0 +1,2 @@ +class Foo { constructor(a: string) { } } +let FooConstructor: { new(): Foo } = Foo;