diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 22b45926cad..dc2d6649013 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -123,8 +123,8 @@ namespace ts { const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const anySignature = createSignature(undefined, undefined, emptyArray, undefined, anyType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); - const unknownSignature = createSignature(undefined, undefined, emptyArray, undefined, unknownType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); + const anySignature = createSignature(undefined, undefined, emptyArray, anyType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); + const unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); const globals: SymbolTable = {}; @@ -3374,13 +3374,12 @@ namespace ts { resolveObjectTypeMembers(type, source, typeParameters, typeArguments); } - function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], parameters: Symbol[], kind: SignatureKind, + function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], parameters: Symbol[], resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature { const sig = new Signature(checker); sig.declaration = declaration; sig.typeParameters = typeParameters; sig.parameters = parameters; - sig.kind = kind; sig.resolvedReturnType = resolvedReturnType; sig.typePredicate = typePredicate; sig.minArgumentCount = minArgumentCount; @@ -3390,13 +3389,13 @@ namespace ts { } function cloneSignature(sig: Signature): Signature { - return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.kind, sig.resolvedReturnType, sig.typePredicate, + return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType, sig.typePredicate, sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals); } function getDefaultConstructSignatures(classType: InterfaceType): Signature[] { if (!hasClassBaseType(classType)) { - return [createSignature(undefined, classType.localTypeParameters, emptyArray, SignatureKind.Construct, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; + return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; } const baseConstructorType = getBaseConstructorTypeOfClass(classType); const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); @@ -3932,33 +3931,7 @@ namespace ts { } } - let kind: SignatureKind; - switch (declaration.kind) { - case SyntaxKind.Constructor: - case SyntaxKind.ConstructSignature: - case SyntaxKind.ConstructorType: - kind = SignatureKind.Construct; - break; - default: - if (declaration.symbol.inferredConstructor) { - kind = SignatureKind.Construct; - const members = createSymbolTable(emptyArray); - // Collect methods declared with className.protoype.methodName = ... - const proto = declaration.symbol.exports["prototype"]; - if (proto) { - mergeSymbolTable(members, proto.members); - } - // Collect properties defined in the constructor by this.propName = ... - mergeSymbolTable(members, declaration.symbol.members); - returnType = createAnonymousType(declaration.symbol, members, emptyArray, emptyArray, undefined, undefined); - } - else { - kind = SignatureKind.Call; - } - break; - } - - links.resolvedSignature = createSignature(declaration, typeParameters, parameters, kind, returnType, typePredicate, + links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, typePredicate, minArgumentCount, hasRestParameter(declaration), hasStringLiterals); } return links.resolvedSignature; @@ -3966,7 +3939,7 @@ namespace ts { function getSignaturesOfSymbol(symbol: Symbol): Signature[] { if (!symbol) return emptyArray; - let result: Signature[] = []; + const result: Signature[] = []; for (let i = 0, len = symbol.declarations.length; i < len; i++) { const node = symbol.declarations[i]; switch (node.kind) { @@ -3993,12 +3966,6 @@ namespace ts { } } result.push(getSignatureFromDeclaration(node)); - break; - - case SyntaxKind.PropertyAccessExpression: - // Inferred class method - result = getSignaturesOfType(checkExpressionCached((node.parent).right), SignatureKind.Call); - break; } } return result; @@ -4081,7 +4048,7 @@ namespace ts { // object type literal or interface (using the new keyword). Each way of declaring a constructor // will result in a different declaration kind. if (!signature.isolatedSignatureType) { - const isConstructor = signature.kind === SignatureKind.Construct; + const isConstructor = signature.declaration.kind === SyntaxKind.Constructor || signature.declaration.kind === SyntaxKind.ConstructSignature; const type = createObjectType(TypeFlags.Anonymous | TypeFlags.FromSignature); type.members = emptySymbols; type.properties = emptyArray; @@ -4784,7 +4751,6 @@ namespace ts { } const result = createSignature(signature.declaration, freshTypeParameters, instantiateList(signature.parameters, mapper, instantiateSymbol), - signature.kind, instantiateType(signature.resolvedReturnType, mapper), freshTypePredicate, signature.minArgumentCount, signature.hasRestParameter, signature.hasStringLiterals); @@ -6838,14 +6804,7 @@ namespace ts { let container: Node; if (symbol.flags & SymbolFlags.Class) { // get parent of class declaration - const classDeclaration = getClassLikeDeclarationOfSymbol(symbol); - if (classDeclaration) { - container = classDeclaration.parent; - } - else { - // JS-inferred class; do nothing - return; - } + container = getClassLikeDeclarationOfSymbol(symbol).parent; } else { // nesting structure: @@ -7189,10 +7148,7 @@ namespace ts { const operator = binaryExpression.operatorToken.kind; if (operator >= SyntaxKind.FirstAssignment && operator <= SyntaxKind.LastAssignment) { // In an assignment expression, the right operand is contextually typed by the type of the left operand. - // In JS files where a special assignment is taking place, don't contextually type the RHS to avoid - // incorrectly assuming a circular 'any' (the type of the LHS is determined by the RHS) - if (node === binaryExpression.right && - !(node.parserContextFlags & ParserContextFlags.JavaScriptFile && getSpecialPropertyAssignmentKind(binaryExpression))) { + if (node === binaryExpression.right) { return checkExpression(binaryExpression.left); } } @@ -9676,9 +9632,21 @@ namespace ts { return voidType; } if (node.kind === SyntaxKind.NewExpression) { - if (signature.kind === SignatureKind.Call) { - // When resolved signature is a call signature (and not a construct signature) the result type is any - if (compilerOptions.noImplicitAny) { + const declaration = signature.declaration; + + if (declaration && + declaration.kind !== SyntaxKind.Constructor && + declaration.kind !== SyntaxKind.ConstructSignature && + declaration.kind !== SyntaxKind.ConstructorType) { + + // When resolved signature is a call signature (and not a construct signature) the result type is any, unless + // the declaring function had members created through 'x.prototype.y = expr' or 'this.y = expr' psuedodeclarations + // in a JS file + const funcSymbol = checkExpression(node.expression).symbol; + if (funcSymbol && funcSymbol.members && (funcSymbol.flags & SymbolFlags.Function)) { + return createAnonymousType(undefined, funcSymbol.members, emptyArray, emptyArray, /*stringIndexType*/ undefined, /*numberIndexType*/ undefined); + } + else if (compilerOptions.noImplicitAny) { error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); } return anyType; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 169ce4acfda..34e862768d0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2237,7 +2237,6 @@ namespace ts { declaration: SignatureDeclaration; // Originating declaration typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic) parameters: Symbol[]; // Parameters - kind: SignatureKind; // Call or Construct typePredicate?: TypePredicate; // Type predicate /* @internal */ resolvedReturnType: Type; // Resolved return type diff --git a/src/services/services.ts b/src/services/services.ts index e145406ac18..4e0a0265b91 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -741,7 +741,6 @@ namespace ts { declaration: SignatureDeclaration; typeParameters: TypeParameter[]; parameters: Symbol[]; - kind: SignatureKind; resolvedReturnType: Type; minArgumentCount: number; hasRestParameter: boolean; diff --git a/tests/cases/fourslash/javaScriptPrototype1.ts b/tests/cases/fourslash/javaScriptPrototype1.ts index 0473d18aae8..c9c454cfb2c 100644 --- a/tests/cases/fourslash/javaScriptPrototype1.ts +++ b/tests/cases/fourslash/javaScriptPrototype1.ts @@ -22,8 +22,8 @@ // Members of the class instance goTo.marker('1'); edit.insert('.'); -verify.memberListContains('foo', undefined, undefined, 'method'); -verify.memberListContains('bar', undefined, undefined, 'method'); +verify.memberListContains('foo', undefined, undefined, 'property'); +verify.memberListContains('bar', undefined, undefined, 'property'); edit.backspace(); // Members of a class method (1) diff --git a/tests/cases/fourslash/javaScriptPrototype3.ts b/tests/cases/fourslash/javaScriptPrototype3.ts deleted file mode 100644 index 900a39ddce9..00000000000 --- a/tests/cases/fourslash/javaScriptPrototype3.ts +++ /dev/null @@ -1,40 +0,0 @@ -/// - -// ES6 classes can extend from JS classes - -// @allowNonTsExtensions: true -// @Filename: myMod.js -//// function myCtor(x) { -//// this.qua = 10; -//// } -//// myCtor.prototype.foo = function() { return 32 }; -//// myCtor.prototype.bar = function() { return '' }; -//// -//// class MyClass extends myCtor { -//// fn() { -//// this/*1*/ -//// let y = super.foo(); -//// y; -//// } -//// } -//// var n = new MyClass(3); -//// n/*2*/; - -goTo.marker('1'); -edit.insert('.'); -// Current class method -verify.completionListContains('fn', undefined, undefined, 'method'); -// Base class method -verify.completionListContains('foo', undefined, undefined, 'method'); -// Base class instance property -verify.completionListContains('qua', undefined, undefined, 'property'); -edit.backspace(); - -// Derived class instance from outside the class -goTo.marker('2'); -edit.insert('.'); -verify.completionListContains('fn', undefined, undefined, 'method'); -// Base class method -verify.completionListContains('foo', undefined, undefined, 'method'); -// Base class instance property -verify.completionListContains('qua', undefined, undefined, 'property'); diff --git a/tests/cases/fourslash/javaScriptPrototype4.ts b/tests/cases/fourslash/javaScriptPrototype4.ts index 3ed723740b4..81cb5fe3784 100644 --- a/tests/cases/fourslash/javaScriptPrototype4.ts +++ b/tests/cases/fourslash/javaScriptPrototype4.ts @@ -16,15 +16,6 @@ goTo.marker('1'); edit.insert('.'); // Check members of the function -verify.completionListContains('prototype', undefined, undefined, 'property'); verify.completionListContains('foo', undefined, undefined, 'warning'); verify.completionListContains('bar', undefined, undefined, 'warning'); verify.completionListContains('qua', undefined, undefined, 'warning'); - -// Check members of function.prototype -edit.insert('prototype.'); -verify.completionListContains('foo', undefined, undefined, 'method'); -verify.completionListContains('bar', undefined, undefined, 'method'); -verify.completionListContains('qua', undefined, undefined, 'warning'); -verify.completionListContains('prototype', undefined, undefined, 'warning'); -