@@ -2924,7 +2924,12 @@ namespace ts {
29242924 if (func.kind === SyntaxKind.SetAccessor && !hasDynamicName(func)) {
29252925 const getter = <AccessorDeclaration>getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor);
29262926 if (getter) {
2927- return getReturnTypeOfSignature(getSignatureFromDeclaration(getter));
2927+ const signature = getSignatureFromDeclaration(getter);
2928+ const thisParameter = getAccessorThisParameter(func as AccessorDeclaration);
2929+ if (thisParameter && declaration === thisParameter) {
2930+ return signature.thisType;
2931+ }
2932+ return getReturnTypeOfSignature(signature);
29282933 }
29292934 }
29302935 // Use contextual parameter type if one is available
@@ -3140,6 +3145,16 @@ namespace ts {
31403145 return undefined;
31413146 }
31423147
3148+ function getAnnotatedAccessorThisType(accessor: AccessorDeclaration): Type {
3149+ if (accessor) {
3150+ const parameter = getAccessorThisParameter(accessor);
3151+ if (parameter && parameter.type) {
3152+ return getTypeFromTypeNode(accessor.parameters[0].type);
3153+ }
3154+ }
3155+ return undefined;
3156+ }
3157+
31433158 function getTypeOfAccessors(symbol: Symbol): Type {
31443159 const links = getSymbolLinks(symbol);
31453160 if (!links.type) {
@@ -4361,20 +4376,12 @@ namespace ts {
43614376 function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature {
43624377 const links = getNodeLinks(declaration);
43634378 if (!links.resolvedSignature) {
4364- const classType = declaration.kind === SyntaxKind.Constructor ?
4365- getDeclaredTypeOfClassOrInterface(getMergedSymbol((<ClassDeclaration>declaration.parent).symbol))
4366- : undefined;
4367- const typeParameters = classType ? classType.localTypeParameters :
4368- declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) :
4369- getTypeParametersFromJSDocTemplate(declaration);
43704379 const parameters: Symbol[] = [];
43714380 let hasStringLiterals = false;
43724381 let minArgumentCount = -1;
43734382 let thisType: Type = undefined;
43744383 let hasThisParameter: boolean;
43754384 const isJSConstructSignature = isJSDocConstructSignature(declaration);
4376- let returnType: Type = undefined;
4377- let typePredicate: TypePredicate = undefined;
43784385
43794386 // If this is a JSDoc construct signature, then skip the first parameter in the
43804387 // parameter list. The first parameter represents the return type of the construct
@@ -4411,48 +4418,68 @@ namespace ts {
44114418 }
44124419 }
44134420
4421+ // If only one accessor includes a this-type annotation, the other behaves as if it had the same type annotation
4422+ if ((declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) &&
4423+ !hasDynamicName(declaration) &&
4424+ (!hasThisParameter || thisType === unknownType)) {
4425+ const otherKind = declaration.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
4426+ const setter = <AccessorDeclaration>getDeclarationOfKind(declaration.symbol, otherKind);
4427+ thisType = getAnnotatedAccessorThisType(setter);
4428+ }
4429+
44144430 if (minArgumentCount < 0) {
44154431 minArgumentCount = declaration.parameters.length - (hasThisParameter ? 1 : 0);
44164432 }
4417-
44184433 if (isJSConstructSignature) {
44194434 minArgumentCount--;
4420- returnType = getTypeFromTypeNode(declaration.parameters[0].type);
44214435 }
4422- else if (classType) {
4423- returnType = classType;
4424- }
4425- else if (declaration.type) {
4426- returnType = getTypeFromTypeNode(declaration.type);
4427- if (declaration.type.kind === SyntaxKind.TypePredicate) {
4428- typePredicate = createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode);
4429- }
4430- }
4431- else {
4432- if (declaration.flags & NodeFlags.JavaScriptFile) {
4433- const type = getReturnTypeFromJSDocComment(declaration);
4434- if (type && type !== unknownType) {
4435- returnType = type;
4436- }
4437- }
4438-
4439- // TypeScript 1.0 spec (April 2014):
4440- // If only one accessor includes a type annotation, the other behaves as if it had the same type annotation.
4441- if (declaration.kind === SyntaxKind.GetAccessor && !hasDynamicName(declaration)) {
4442- const setter = <AccessorDeclaration>getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor);
4443- returnType = getAnnotatedAccessorType(setter);
4444- }
44454436
4446- if (!returnType && nodeIsMissing((<FunctionLikeDeclaration>declaration).body)) {
4447- returnType = anyType;
4448- }
4449- }
4437+ const classType = declaration.kind === SyntaxKind.Constructor ?
4438+ getDeclaredTypeOfClassOrInterface(getMergedSymbol((<ClassDeclaration>declaration.parent).symbol))
4439+ : undefined;
4440+ const typeParameters = classType ? classType.localTypeParameters :
4441+ declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) :
4442+ getTypeParametersFromJSDocTemplate(declaration);
4443+ const returnType = getSignatureReturnTypeFromDeclaration(declaration, minArgumentCount, isJSConstructSignature, classType);
4444+ const typePredicate = declaration.type && declaration.type.kind === SyntaxKind.TypePredicate ?
4445+ createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode) :
4446+ undefined;
44504447
44514448 links.resolvedSignature = createSignature(declaration, typeParameters, thisType, parameters, returnType, typePredicate, minArgumentCount, hasRestParameter(declaration), hasStringLiterals);
44524449 }
44534450 return links.resolvedSignature;
44544451 }
44554452
4453+ function getSignatureReturnTypeFromDeclaration(declaration: SignatureDeclaration, minArgumentCount: number, isJSConstructSignature: boolean, classType: Type) {
4454+ if (isJSConstructSignature) {
4455+ return getTypeFromTypeNode(declaration.parameters[0].type);
4456+ }
4457+ else if (classType) {
4458+ return classType;
4459+ }
4460+ else if (declaration.type) {
4461+ return getTypeFromTypeNode(declaration.type);
4462+ }
4463+
4464+ if (declaration.flags & NodeFlags.JavaScriptFile) {
4465+ const type = getReturnTypeFromJSDocComment(declaration);
4466+ if (type && type !== unknownType) {
4467+ return type;
4468+ }
4469+ }
4470+
4471+ // TypeScript 1.0 spec (April 2014):
4472+ // If only one accessor includes a type annotation, the other behaves as if it had the same type annotation.
4473+ if (declaration.kind === SyntaxKind.GetAccessor && !hasDynamicName(declaration)) {
4474+ const setter = <AccessorDeclaration>getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor);
4475+ return getAnnotatedAccessorType(setter);
4476+ }
4477+
4478+ if (nodeIsMissing((<FunctionLikeDeclaration>declaration).body)) {
4479+ return anyType;
4480+ }
4481+ }
4482+
44564483 function getSignaturesOfSymbol(symbol: Symbol): Signature[] {
44574484 if (!symbol) return emptyArray;
44584485 const result: Signature[] = [];
@@ -12644,9 +12671,6 @@ namespace ts {
1264412671 if (func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature || func.kind === SyntaxKind.ConstructorType) {
1264512672 error(node, Diagnostics.A_constructor_cannot_have_a_this_parameter);
1264612673 }
12647- if (func.kind === SyntaxKind.SetAccessor) {
12648- error(node, Diagnostics.A_setter_cannot_have_a_this_parameter);
12649- }
1265012674 }
1265112675
1265212676 // Only check rest parameter type if it's not a binding pattern. Since binding patterns are
@@ -13033,15 +13057,10 @@ namespace ts {
1303313057 error(node.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract);
1303413058 }
1303513059
13036- const currentAccessorType = getAnnotatedAccessorType(node);
13037- const otherAccessorType = getAnnotatedAccessorType(otherAccessor);
1303813060 // TypeScript 1.0 spec (April 2014): 4.5
1303913061 // If both accessors include type annotations, the specified types must be identical.
13040- if (currentAccessorType && otherAccessorType) {
13041- if (!isTypeIdenticalTo(currentAccessorType, otherAccessorType)) {
13042- error(node, Diagnostics.get_and_set_accessor_must_have_the_same_type);
13043- }
13044- }
13062+ checkAccessorDeclarationTypesIdentical(node, otherAccessor, getAnnotatedAccessorType, Diagnostics.get_and_set_accessor_must_have_the_same_type);
13063+ checkAccessorDeclarationTypesIdentical(node, otherAccessor, getAnnotatedAccessorThisType, Diagnostics.get_and_set_accessor_must_have_the_same_this_type);
1304513064 }
1304613065 }
1304713066 getTypeOfAccessors(getSymbolOfNode(node));
@@ -13054,6 +13073,14 @@ namespace ts {
1305413073 }
1305513074 }
1305613075
13076+ function checkAccessorDeclarationTypesIdentical(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type, message: DiagnosticMessage) {
13077+ const firstType = getAnnotatedType(first);
13078+ const secondType = getAnnotatedType(second);
13079+ if (firstType && secondType && !isTypeIdenticalTo(firstType, secondType)) {
13080+ error(first, message);
13081+ }
13082+ }
13083+
1305713084 function checkAccessorDeferred(node: AccessorDeclaration) {
1305813085 checkSourceElement(node.body);
1305913086 }
@@ -18127,7 +18154,7 @@ namespace ts {
1812718154 return false;
1812818155 }
1812918156
18130- function checkGrammarAccessor(accessor: MethodDeclaration ): boolean {
18157+ function checkGrammarAccessor(accessor: AccessorDeclaration ): boolean {
1813118158 const kind = accessor.kind;
1813218159 if (languageVersion < ScriptTarget.ES5) {
1813318160 return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher);
@@ -18141,16 +18168,16 @@ namespace ts {
1814118168 else if (accessor.typeParameters) {
1814218169 return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_have_type_parameters);
1814318170 }
18144- else if (kind === SyntaxKind.GetAccessor && accessor.parameters.length) {
18145- return grammarErrorOnNode(accessor.name, Diagnostics.A_get_accessor_cannot_have_parameters);
18171+ else if (!doesAccessorHaveCorrectParameterCount(accessor)) {
18172+ return grammarErrorOnNode(accessor.name,
18173+ kind === SyntaxKind.GetAccessor ?
18174+ Diagnostics.A_get_accessor_cannot_have_parameters :
18175+ Diagnostics.A_set_accessor_must_have_exactly_one_parameter);
1814618176 }
1814718177 else if (kind === SyntaxKind.SetAccessor) {
1814818178 if (accessor.type) {
1814918179 return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation);
1815018180 }
18151- else if (accessor.parameters.length !== 1) {
18152- return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_must_have_exactly_one_parameter);
18153- }
1815418181 else {
1815518182 const parameter = accessor.parameters[0];
1815618183 if (parameter.dotDotDotToken) {
@@ -18169,6 +18196,22 @@ namespace ts {
1816918196 }
1817018197 }
1817118198
18199+ /** Does the accessor have the right number of parameters?
18200+
18201+ A get accessor has no parameters or a single `this` parameter.
18202+ A set accessor has one parameter or a `this` parameter and one more parameter */
18203+ function doesAccessorHaveCorrectParameterCount(accessor: AccessorDeclaration) {
18204+ return getAccessorThisParameter(accessor) || accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 0 : 1);
18205+ }
18206+
18207+ function getAccessorThisParameter(accessor: AccessorDeclaration) {
18208+ if (accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 1 : 2) &&
18209+ accessor.parameters[0].name.kind === SyntaxKind.Identifier &&
18210+ (<Identifier>accessor.parameters[0].name).originalKeywordKind === SyntaxKind.ThisKeyword) {
18211+ return accessor.parameters[0];
18212+ }
18213+ }
18214+
1817218215 function checkGrammarForNonSymbolComputedProperty(node: DeclarationName, message: DiagnosticMessage) {
1817318216 if (isDynamicName(node)) {
1817418217 return grammarErrorOnNode(node, message);
0 commit comments