diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cfe2c5a6bf2..a3f8b9facad 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15835,7 +15835,7 @@ namespace ts { const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call); if (callSignatures.length) { const signature = resolveCall(node, callSignatures, candidatesOutArray); - if (getReturnTypeOfSignature(signature) !== voidType) { + if (!isInJavaScriptFile(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) { error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword); } if (getThisTypeOfSignature(signature) === voidType) { diff --git a/tests/baselines/reference/jsConstructorFunction.symbols b/tests/baselines/reference/jsConstructorFunction.symbols new file mode 100644 index 00000000000..d4954b1abdc --- /dev/null +++ b/tests/baselines/reference/jsConstructorFunction.symbols @@ -0,0 +1,56 @@ +=== tests/cases/compiler/index.js === +var Person = function (firstNameOrPojo, lastName) { +>Person : Symbol(Person, Decl(index.js, 0, 3)) +>firstNameOrPojo : Symbol(firstNameOrPojo, Decl(index.js, 0, 23)) +>lastName : Symbol(lastName, Decl(index.js, 0, 39)) + + if (typeof firstNameOrPojo === "string") { +>firstNameOrPojo : Symbol(firstNameOrPojo, Decl(index.js, 0, 23)) + + this.firstName = firstNameOrPojo; +>firstName : Symbol(Person.firstName, Decl(index.js, 2, 46)) +>firstNameOrPojo : Symbol(firstNameOrPojo, Decl(index.js, 0, 23)) + + this.lastName = lastName; +>lastName : Symbol(Person.lastName, Decl(index.js, 3, 41)) +>lastName : Symbol(lastName, Decl(index.js, 0, 39)) + + } else { + return new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName); +>Person : Symbol(Person, Decl(index.js, 0, 3)) +>firstNameOrPojo : Symbol(firstNameOrPojo, Decl(index.js, 0, 23)) +>firstNameOrPojo : Symbol(firstNameOrPojo, Decl(index.js, 0, 23)) + } +}; + +Person.prototype.greet = function greet() { +>Person.prototype : Symbol(Person.greet, Decl(index.js, 8, 2)) +>Person : Symbol(Person, Decl(index.js, 0, 3)) +>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --)) +>greet : Symbol(Person.greet, Decl(index.js, 8, 2)) +>greet : Symbol(greet, Decl(index.js, 10, 24)) + + return `Hello, I am ${this.firstName} ${this.lastName}.`; +>this.firstName : Symbol(Person.firstName, Decl(index.js, 2, 46)) +>this : Symbol(Person, Decl(index.js, 0, 12)) +>firstName : Symbol(Person.firstName, Decl(index.js, 2, 46)) +>this.lastName : Symbol(Person.lastName, Decl(index.js, 3, 41)) +>this : Symbol(Person, Decl(index.js, 0, 12)) +>lastName : Symbol(Person.lastName, Decl(index.js, 3, 41)) + +}; + +var fred = new Person({ firstName: "Fred", lastName: "Flintstone" }); +>fred : Symbol(fred, Decl(index.js, 14, 3)) +>Person : Symbol(Person, Decl(index.js, 0, 3)) +>firstName : Symbol(firstName, Decl(index.js, 14, 23)) +>lastName : Symbol(lastName, Decl(index.js, 14, 42)) + +console.log(fred.greet()); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>fred.greet : Symbol(Person.greet, Decl(index.js, 8, 2)) +>fred : Symbol(fred, Decl(index.js, 14, 3)) +>greet : Symbol(Person.greet, Decl(index.js, 8, 2)) + diff --git a/tests/baselines/reference/jsConstructorFunction.types b/tests/baselines/reference/jsConstructorFunction.types new file mode 100644 index 00000000000..3c2854ac87f --- /dev/null +++ b/tests/baselines/reference/jsConstructorFunction.types @@ -0,0 +1,81 @@ +=== tests/cases/compiler/index.js === +var Person = function (firstNameOrPojo, lastName) { +>Person : (firstNameOrPojo: any, lastName: any) => any +>function (firstNameOrPojo, lastName) { if (typeof firstNameOrPojo === "string") { this.firstName = firstNameOrPojo; this.lastName = lastName; } else { return new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName); }} : (firstNameOrPojo: any, lastName: any) => any +>firstNameOrPojo : any +>lastName : any + + if (typeof firstNameOrPojo === "string") { +>typeof firstNameOrPojo === "string" : boolean +>typeof firstNameOrPojo : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" +>firstNameOrPojo : any +>"string" : "string" + + this.firstName = firstNameOrPojo; +>this.firstName = firstNameOrPojo : string +>this.firstName : any +>this : any +>firstName : any +>firstNameOrPojo : string + + this.lastName = lastName; +>this.lastName = lastName : any +>this.lastName : any +>this : any +>lastName : any +>lastName : any + + } else { + return new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName); +>new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName) : { firstName: string; lastName: any; greet: () => string; } +>Person : (firstNameOrPojo: any, lastName: any) => any +>firstNameOrPojo.firstName : any +>firstNameOrPojo : any +>firstName : any +>firstNameOrPojo.lastName : any +>firstNameOrPojo : any +>lastName : any + } +}; + +Person.prototype.greet = function greet() { +>Person.prototype.greet = function greet() { return `Hello, I am ${this.firstName} ${this.lastName}.`;} : () => string +>Person.prototype.greet : any +>Person.prototype : any +>Person : (firstNameOrPojo: any, lastName: any) => any +>prototype : any +>greet : any +>function greet() { return `Hello, I am ${this.firstName} ${this.lastName}.`;} : () => string +>greet : () => string + + return `Hello, I am ${this.firstName} ${this.lastName}.`; +>`Hello, I am ${this.firstName} ${this.lastName}.` : string +>this.firstName : string +>this : { firstName: string; lastName: any; greet: () => string; } +>firstName : string +>this.lastName : any +>this : { firstName: string; lastName: any; greet: () => string; } +>lastName : any + +}; + +var fred = new Person({ firstName: "Fred", lastName: "Flintstone" }); +>fred : { firstName: string; lastName: any; greet: () => string; } +>new Person({ firstName: "Fred", lastName: "Flintstone" }) : { firstName: string; lastName: any; greet: () => string; } +>Person : (firstNameOrPojo: any, lastName: any) => any +>{ firstName: "Fred", lastName: "Flintstone" } : { firstName: string; lastName: string; } +>firstName : string +>"Fred" : "Fred" +>lastName : string +>"Flintstone" : "Flintstone" + +console.log(fred.greet()); +>console.log(fred.greet()) : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>fred.greet() : string +>fred.greet : () => string +>fred : { firstName: string; lastName: any; greet: () => string; } +>greet : () => string + diff --git a/tests/cases/compiler/jsConstructorFunction.ts b/tests/cases/compiler/jsConstructorFunction.ts new file mode 100644 index 00000000000..2cb0d16b766 --- /dev/null +++ b/tests/cases/compiler/jsConstructorFunction.ts @@ -0,0 +1,22 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @filename: index.js +// @lib: es5, dom +var Person = function (firstNameOrPojo, lastName) { + + if (typeof firstNameOrPojo === "string") { + this.firstName = firstNameOrPojo; + this.lastName = lastName; + } else { + return new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName); + } +}; + +Person.prototype.greet = function greet() { + return `Hello, I am ${this.firstName} ${this.lastName}.`; +}; + +var fred = new Person({ firstName: "Fred", lastName: "Flintstone" }); + +console.log(fred.greet()); \ No newline at end of file