@@ -3136,6 +3136,17 @@ namespace ts {
31363136 return undefined;
31373137 }
31383138
3139+ function getAnnotatedAccessorThisType(accessor: AccessorDeclaration): Type {
3140+ if (accessor &&
3141+ accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 1 : 2) &&
3142+ accessor.parameters[0].name.kind === SyntaxKind.Identifier &&
3143+ (accessor.parameters[0].name as Identifier).originalKeywordKind === SyntaxKind.ThisKeyword &&
3144+ accessor.parameters[0].type ) {
3145+ return getTypeFromTypeNode(accessor.parameters[0].type);
3146+ }
3147+ return undefined;
3148+ }
3149+
31393150 function getTypeOfAccessors(symbol: Symbol): Type {
31403151 const links = getSymbolLinks(symbol);
31413152 if (!links.type) {
@@ -4357,20 +4368,12 @@ namespace ts {
43574368 function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature {
43584369 const links = getNodeLinks(declaration);
43594370 if (!links.resolvedSignature) {
4360- const classType = declaration.kind === SyntaxKind.Constructor ?
4361- getDeclaredTypeOfClassOrInterface(getMergedSymbol((<ClassDeclaration>declaration.parent).symbol))
4362- : undefined;
4363- const typeParameters = classType ? classType.localTypeParameters :
4364- declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) :
4365- getTypeParametersFromJSDocTemplate(declaration);
43664371 const parameters: Symbol[] = [];
43674372 let hasStringLiterals = false;
43684373 let minArgumentCount = -1;
43694374 let thisType: Type = undefined;
43704375 let hasThisParameter: boolean;
43714376 const isJSConstructSignature = isJSDocConstructSignature(declaration);
4372- let returnType: Type = undefined;
4373- let typePredicate: TypePredicate = undefined;
43744377
43754378 // If this is a JSDoc construct signature, then skip the first parameter in the
43764379 // parameter list. The first parameter represents the return type of the construct
@@ -4407,48 +4410,68 @@ namespace ts {
44074410 }
44084411 }
44094412
4413+ // If only one accessor includes a this-type annotation, the other behaves as if it had the same type annotation
4414+ if ((declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) &&
4415+ !hasDynamicName(declaration) &&
4416+ !hasThisParameter) {
4417+ const otherKind = declaration.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
4418+ const setter = <AccessorDeclaration>getDeclarationOfKind(declaration.symbol, otherKind);
4419+ thisType = getAnnotatedAccessorThisType(setter);
4420+ }
4421+
44104422 if (minArgumentCount < 0) {
44114423 minArgumentCount = declaration.parameters.length - (hasThisParameter ? 1 : 0);
44124424 }
4413-
44144425 if (isJSConstructSignature) {
44154426 minArgumentCount--;
4416- returnType = getTypeFromTypeNode(declaration.parameters[0].type);
4417- }
4418- else if (classType) {
4419- returnType = classType;
44204427 }
4421- else if (declaration.type) {
4422- returnType = getTypeFromTypeNode(declaration.type);
4423- if (declaration.type.kind === SyntaxKind.TypePredicate) {
4424- typePredicate = createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode);
4425- }
4426- }
4427- else {
4428- if (declaration.flags & NodeFlags.JavaScriptFile) {
4429- const type = getReturnTypeFromJSDocComment(declaration);
4430- if (type && type !== unknownType) {
4431- returnType = type;
4432- }
4433- }
4434-
4435- // TypeScript 1.0 spec (April 2014):
4436- // If only one accessor includes a type annotation, the other behaves as if it had the same type annotation.
4437- if (declaration.kind === SyntaxKind.GetAccessor && !hasDynamicName(declaration)) {
4438- const setter = <AccessorDeclaration>getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor);
4439- returnType = getAnnotatedAccessorType(setter);
4440- }
44414428
4442- if (!returnType && nodeIsMissing((<FunctionLikeDeclaration>declaration).body)) {
4443- returnType = anyType;
4444- }
4445- }
4429+ const classType = declaration.kind === SyntaxKind.Constructor ?
4430+ getDeclaredTypeOfClassOrInterface(getMergedSymbol((<ClassDeclaration>declaration.parent).symbol))
4431+ : undefined;
4432+ const typeParameters = classType ? classType.localTypeParameters :
4433+ declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) :
4434+ getTypeParametersFromJSDocTemplate(declaration);
4435+ const returnType = getSignatureReturnTypeFromDeclaration(declaration, minArgumentCount, isJSConstructSignature, classType);
4436+ const typePredicate = declaration.type && declaration.type.kind === SyntaxKind.TypePredicate ?
4437+ createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode) :
4438+ undefined;
44464439
44474440 links.resolvedSignature = createSignature(declaration, typeParameters, thisType, parameters, returnType, typePredicate, minArgumentCount, hasRestParameter(declaration), hasStringLiterals);
44484441 }
44494442 return links.resolvedSignature;
44504443 }
44514444
4445+ function getSignatureReturnTypeFromDeclaration(declaration: SignatureDeclaration, minArgumentCount: number, isJSConstructSignature: boolean, classType: Type) {
4446+ if (isJSConstructSignature) {
4447+ return getTypeFromTypeNode(declaration.parameters[0].type);
4448+ }
4449+ else if (classType) {
4450+ return classType;
4451+ }
4452+ else if (declaration.type) {
4453+ return getTypeFromTypeNode(declaration.type);
4454+ }
4455+
4456+ if (declaration.flags & NodeFlags.JavaScriptFile) {
4457+ const type = getReturnTypeFromJSDocComment(declaration);
4458+ if (type && type !== unknownType) {
4459+ return type;
4460+ }
4461+ }
4462+
4463+ // TypeScript 1.0 spec (April 2014):
4464+ // If only one accessor includes a type annotation, the other behaves as if it had the same type annotation.
4465+ if (declaration.kind === SyntaxKind.GetAccessor && !hasDynamicName(declaration)) {
4466+ const setter = <AccessorDeclaration>getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor);
4467+ return getAnnotatedAccessorType(setter);
4468+ }
4469+
4470+ if (nodeIsMissing((<FunctionLikeDeclaration>declaration).body)) {
4471+ return anyType;
4472+ }
4473+ }
4474+
44524475 function getSignaturesOfSymbol(symbol: Symbol): Signature[] {
44534476 if (!symbol) return emptyArray;
44544477 const result: Signature[] = [];
@@ -12571,9 +12594,6 @@ namespace ts {
1257112594 if (func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature || func.kind === SyntaxKind.ConstructorType) {
1257212595 error(node, Diagnostics.A_constructor_cannot_have_a_this_parameter);
1257312596 }
12574- if (func.kind === SyntaxKind.SetAccessor) {
12575- error(node, Diagnostics.A_setter_cannot_have_a_this_parameter);
12576- }
1257712597 }
1257812598
1257912599 // Only check rest parameter type if it's not a binding pattern. Since binding patterns are
@@ -12960,15 +12980,10 @@ namespace ts {
1296012980 error(node.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract);
1296112981 }
1296212982
12963- const currentAccessorType = getAnnotatedAccessorType(node);
12964- const otherAccessorType = getAnnotatedAccessorType(otherAccessor);
1296512983 // TypeScript 1.0 spec (April 2014): 4.5
1296612984 // If both accessors include type annotations, the specified types must be identical.
12967- if (currentAccessorType && otherAccessorType) {
12968- if (!isTypeIdenticalTo(currentAccessorType, otherAccessorType)) {
12969- error(node, Diagnostics.get_and_set_accessor_must_have_the_same_type);
12970- }
12971- }
12985+ checkAccessorDeclarationTypesIdentical(node, otherAccessor, getAnnotatedAccessorType, Diagnostics.get_and_set_accessor_must_have_the_same_type);
12986+ checkAccessorDeclarationTypesIdentical(node, otherAccessor, getAnnotatedAccessorThisType, Diagnostics.get_and_set_accessor_must_have_the_same_this_type);
1297212987 }
1297312988 }
1297412989 getTypeOfAccessors(getSymbolOfNode(node));
@@ -12981,6 +12996,14 @@ namespace ts {
1298112996 }
1298212997 }
1298312998
12999+ function checkAccessorDeclarationTypesIdentical(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type, message: DiagnosticMessage) {
13000+ const firstType = getAnnotatedType(first);
13001+ const secondType = getAnnotatedType(second);
13002+ if (firstType && secondType && !isTypeIdenticalTo(firstType, secondType)) {
13003+ error(first, message);
13004+ }
13005+ }
13006+
1298413007 function checkAccessorDeferred(node: AccessorDeclaration) {
1298513008 checkSourceElement(node.body);
1298613009 }
@@ -18075,16 +18098,16 @@ namespace ts {
1807518098 else if (accessor.typeParameters) {
1807618099 return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_have_type_parameters);
1807718100 }
18078- else if (kind === SyntaxKind.GetAccessor && accessor.parameters.length) {
18079- return grammarErrorOnNode(accessor.name, Diagnostics.A_get_accessor_cannot_have_parameters);
18101+ else if (!doesAccessorHaveCorrectParameterCount(accessor)) {
18102+ return grammarErrorOnNode(accessor.name,
18103+ kind === SyntaxKind.GetAccessor ?
18104+ Diagnostics.A_get_accessor_cannot_have_parameters :
18105+ Diagnostics.A_set_accessor_must_have_exactly_one_parameter);
1808018106 }
1808118107 else if (kind === SyntaxKind.SetAccessor) {
1808218108 if (accessor.type) {
1808318109 return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation);
1808418110 }
18085- else if (accessor.parameters.length !== 1) {
18086- return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_must_have_exactly_one_parameter);
18087- }
1808818111 else {
1808918112 const parameter = accessor.parameters[0];
1809018113 if (parameter.dotDotDotToken) {
@@ -18103,6 +18126,18 @@ namespace ts {
1810318126 }
1810418127 }
1810518128
18129+ /** Does the accessor have the right number of parameters?
18130+
18131+ A get accessor has no parameters or a single `this` parameter.
18132+ A set accessor has one parameter or a `this` parameter and one more parameter */
18133+ function doesAccessorHaveCorrectParameterCount(accessor: MethodDeclaration) {
18134+ const isGet = accessor.kind === SyntaxKind.GetAccessor;
18135+ return (accessor.parameters.length === (isGet ? 1 : 2) &&
18136+ accessor.parameters[0].name.kind === SyntaxKind.Identifier &&
18137+ (<Identifier>accessor.parameters[0].name).originalKeywordKind === SyntaxKind.ThisKeyword) ||
18138+ accessor.parameters.length === (isGet ? 0 : 1);
18139+ }
18140+
1810618141 function checkGrammarForNonSymbolComputedProperty(node: DeclarationName, message: DiagnosticMessage) {
1810718142 if (isDynamicName(node)) {
1810818143 return grammarErrorOnNode(node, message);
0 commit comments