diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index eee26f894dca4..e17b38ff736d7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5674,7 +5674,18 @@ namespace ts { return type.resolvedBaseConstructorType = errorType; } if (!(baseConstructorType.flags & TypeFlags.Any) && baseConstructorType !== nullWideningType && !isConstructorType(baseConstructorType)) { - error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType)); + const err = error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType)); + if (baseConstructorType.flags & TypeFlags.TypeParameter) { + const constraint = getConstraintFromTypeParameter(baseConstructorType); + let ctorReturn: Type = unknownType; + if (constraint) { + const ctorSig = getSignaturesOfType(constraint, SignatureKind.Construct); + if (ctorSig[0]) { + ctorReturn = getReturnTypeOfSignature(ctorSig[0]); + } + } + addRelatedInfo(err, createDiagnosticForNode(baseConstructorType.symbol.declarations[0], Diagnostics.Did_you_mean_for_0_to_be_constrained_to_type_new_args_Colon_any_1, symbolToString(baseConstructorType.symbol), typeToString(ctorReturn))); + } return type.resolvedBaseConstructorType = errorType; } type.resolvedBaseConstructorType = baseConstructorType; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index e2dd0a1b7cd99..6f22515dea776 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2493,6 +2493,10 @@ "category": "Error", "code": 2734 }, + "Did you mean for '{0}' to be constrained to type 'new (...args: any[]) => {1}'?": { + "category": "Error", + "code": 2735 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/baseConstraintOfDecorator.errors.txt b/tests/baselines/reference/baseConstraintOfDecorator.errors.txt index efc0c59f9ee64..3af8756fac29a 100644 --- a/tests/baselines/reference/baseConstraintOfDecorator.errors.txt +++ b/tests/baselines/reference/baseConstraintOfDecorator.errors.txt @@ -1,13 +1,36 @@ tests/cases/compiler/baseConstraintOfDecorator.ts(2,5): error TS2322: Type 'typeof decoratorFunc' is not assignable to type 'TFunction'. tests/cases/compiler/baseConstraintOfDecorator.ts(2,40): error TS2507: Type 'TFunction' is not a constructor function type. +tests/cases/compiler/baseConstraintOfDecorator.ts(12,5): error TS2322: Type 'typeof decoratorFunc' is not assignable to type 'TFunction'. +tests/cases/compiler/baseConstraintOfDecorator.ts(12,40): error TS2507: Type 'TFunction' is not a constructor function type. -==== tests/cases/compiler/baseConstraintOfDecorator.ts (2 errors) ==== +==== tests/cases/compiler/baseConstraintOfDecorator.ts (4 errors) ==== export function classExtender(superClass: TFunction, _instanceModifier: (instance: any, args: any[]) => void): TFunction { return class decoratorFunc extends superClass { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~ !!! error TS2507: Type 'TFunction' is not a constructor function type. +!!! related TS2735 tests/cases/compiler/baseConstraintOfDecorator.ts:1:31: Did you mean for 'TFunction' to be constrained to type 'new (...args: any[]) => unknown'? + constructor(...args: any[]) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + super(...args); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + _instanceModifier(this, args); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~~~~~~~~~ + }; + ~~~~~~ +!!! error TS2322: Type 'typeof decoratorFunc' is not assignable to type 'TFunction'. + } + + class MyClass { private x; } + export function classExtender2 MyClass>(superClass: TFunction, _instanceModifier: (instance: any, args: any[]) => void): TFunction { + return class decoratorFunc extends superClass { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~ +!!! error TS2507: Type 'TFunction' is not a constructor function type. +!!! related TS2735 tests/cases/compiler/baseConstraintOfDecorator.ts:11:32: Did you mean for 'TFunction' to be constrained to type 'new (...args: any[]) => MyClass'? constructor(...args: any[]) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ super(...args); diff --git a/tests/baselines/reference/baseConstraintOfDecorator.js b/tests/baselines/reference/baseConstraintOfDecorator.js index a7f6b6e41cb47..0c1f77e31e693 100644 --- a/tests/baselines/reference/baseConstraintOfDecorator.js +++ b/tests/baselines/reference/baseConstraintOfDecorator.js @@ -7,6 +7,16 @@ export function classExtender(superClass: TFunction, _instanceModifie } }; } + +class MyClass { private x; } +export function classExtender2 MyClass>(superClass: TFunction, _instanceModifier: (instance: any, args: any[]) => void): TFunction { + return class decoratorFunc extends superClass { + constructor(...args: any[]) { + super(...args); + _instanceModifier(this, args); + } + }; +} //// [baseConstraintOfDecorator.js] @@ -41,3 +51,24 @@ function classExtender(superClass, _instanceModifier) { }(superClass)); } exports.classExtender = classExtender; +var MyClass = /** @class */ (function () { + function MyClass() { + } + return MyClass; +}()); +function classExtender2(superClass, _instanceModifier) { + return /** @class */ (function (_super) { + __extends(decoratorFunc, _super); + function decoratorFunc() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var _this = _super.apply(this, args) || this; + _instanceModifier(_this, args); + return _this; + } + return decoratorFunc; + }(superClass)); +} +exports.classExtender2 = classExtender2; diff --git a/tests/baselines/reference/baseConstraintOfDecorator.symbols b/tests/baselines/reference/baseConstraintOfDecorator.symbols index 71d7773a7cf2a..9048d7ed568e8 100644 --- a/tests/baselines/reference/baseConstraintOfDecorator.symbols +++ b/tests/baselines/reference/baseConstraintOfDecorator.symbols @@ -27,3 +27,37 @@ export function classExtender(superClass: TFunction, _instanceModifie }; } +class MyClass { private x; } +>MyClass : Symbol(MyClass, Decl(baseConstraintOfDecorator.ts, 7, 1)) +>x : Symbol(MyClass.x, Decl(baseConstraintOfDecorator.ts, 9, 15)) + +export function classExtender2 MyClass>(superClass: TFunction, _instanceModifier: (instance: any, args: any[]) => void): TFunction { +>classExtender2 : Symbol(classExtender2, Decl(baseConstraintOfDecorator.ts, 9, 28)) +>TFunction : Symbol(TFunction, Decl(baseConstraintOfDecorator.ts, 10, 31)) +>args : Symbol(args, Decl(baseConstraintOfDecorator.ts, 10, 54)) +>MyClass : Symbol(MyClass, Decl(baseConstraintOfDecorator.ts, 7, 1)) +>superClass : Symbol(superClass, Decl(baseConstraintOfDecorator.ts, 10, 85)) +>TFunction : Symbol(TFunction, Decl(baseConstraintOfDecorator.ts, 10, 31)) +>_instanceModifier : Symbol(_instanceModifier, Decl(baseConstraintOfDecorator.ts, 10, 107)) +>instance : Symbol(instance, Decl(baseConstraintOfDecorator.ts, 10, 128)) +>args : Symbol(args, Decl(baseConstraintOfDecorator.ts, 10, 142)) +>TFunction : Symbol(TFunction, Decl(baseConstraintOfDecorator.ts, 10, 31)) + + return class decoratorFunc extends superClass { +>decoratorFunc : Symbol(decoratorFunc, Decl(baseConstraintOfDecorator.ts, 11, 10)) +>superClass : Symbol(superClass, Decl(baseConstraintOfDecorator.ts, 10, 85)) + + constructor(...args: any[]) { +>args : Symbol(args, Decl(baseConstraintOfDecorator.ts, 12, 20)) + + super(...args); +>args : Symbol(args, Decl(baseConstraintOfDecorator.ts, 12, 20)) + + _instanceModifier(this, args); +>_instanceModifier : Symbol(_instanceModifier, Decl(baseConstraintOfDecorator.ts, 10, 107)) +>this : Symbol(decoratorFunc, Decl(baseConstraintOfDecorator.ts, 11, 10)) +>args : Symbol(args, Decl(baseConstraintOfDecorator.ts, 12, 20)) + } + }; +} + diff --git a/tests/baselines/reference/baseConstraintOfDecorator.types b/tests/baselines/reference/baseConstraintOfDecorator.types index edf9641a4ba38..a5a277c5d2a68 100644 --- a/tests/baselines/reference/baseConstraintOfDecorator.types +++ b/tests/baselines/reference/baseConstraintOfDecorator.types @@ -29,3 +29,38 @@ export function classExtender(superClass: TFunction, _instanceModifie }; } +class MyClass { private x; } +>MyClass : MyClass +>x : any + +export function classExtender2 MyClass>(superClass: TFunction, _instanceModifier: (instance: any, args: any[]) => void): TFunction { +>classExtender2 : MyClass>(superClass: TFunction, _instanceModifier: (instance: any, args: any[]) => void) => TFunction +>args : string[] +>superClass : TFunction +>_instanceModifier : (instance: any, args: any[]) => void +>instance : any +>args : any[] + + return class decoratorFunc extends superClass { +>class decoratorFunc extends superClass { constructor(...args: any[]) { super(...args); _instanceModifier(this, args); } } : typeof decoratorFunc +>decoratorFunc : typeof decoratorFunc +>superClass : TFunction + + constructor(...args: any[]) { +>args : any[] + + super(...args); +>super(...args) : void +>super : any +>...args : any +>args : any[] + + _instanceModifier(this, args); +>_instanceModifier(this, args) : void +>_instanceModifier : (instance: any, args: any[]) => void +>this : this +>args : any[] + } + }; +} + diff --git a/tests/cases/compiler/baseConstraintOfDecorator.ts b/tests/cases/compiler/baseConstraintOfDecorator.ts index d8eb00f07da19..9419974a04ff4 100644 --- a/tests/cases/compiler/baseConstraintOfDecorator.ts +++ b/tests/cases/compiler/baseConstraintOfDecorator.ts @@ -6,3 +6,13 @@ export function classExtender(superClass: TFunction, _instanceModifie } }; } + +class MyClass { private x; } +export function classExtender2 MyClass>(superClass: TFunction, _instanceModifier: (instance: any, args: any[]) => void): TFunction { + return class decoratorFunc extends superClass { + constructor(...args: any[]) { + super(...args); + _instanceModifier(this, args); + } + }; +}