@@ -8844,7 +8844,7 @@ namespace ts {
88448844 return links.type;
88458845 }
88468846
8847- function getTypeOfVariableOrParameterOrPropertyWorker(symbol: Symbol) {
8847+ function getTypeOfVariableOrParameterOrPropertyWorker(symbol: Symbol): Type {
88488848 // Handle prototype property
88498849 if (symbol.flags & SymbolFlags.Prototype) {
88508850 return getTypeOfPrototypeProperty(symbol);
@@ -8894,7 +8894,7 @@ namespace ts {
88948894 }
88958895 return reportCircularityError(symbol);
88968896 }
8897- let type: Type | undefined ;
8897+ let type: Type;
88988898 if (declaration.kind === SyntaxKind.ExportAssignment) {
88998899 type = widenTypeForVariableLikeDeclaration(checkExpressionCached((<ExportAssignment>declaration).expression), declaration);
89008900 }
@@ -8951,7 +8951,7 @@ namespace ts {
89518951 type = getTypeOfEnumMember(symbol);
89528952 }
89538953 else if (isAccessor(declaration)) {
8954- type = resolveTypeOfAccessors(symbol);
8954+ type = resolveTypeOfAccessors(symbol) || Debug.fail("Non-write accessor resolution must always produce a type") ;
89558955 }
89568956 else {
89578957 return Debug.fail("Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + Debug.formatSymbol(symbol));
@@ -8997,15 +8997,20 @@ namespace ts {
89978997
89988998 function getTypeOfAccessors(symbol: Symbol): Type {
89998999 const links = getSymbolLinks(symbol);
9000- return links.type || (links.type = getTypeOfAccessorsWorker(symbol));
9000+ return links.type || (links.type = getTypeOfAccessorsWorker(symbol) || Debug.fail("Read type of accessor must always produce a type"));
9001+ }
9002+
9003+ function getTypeOfSetAccessor(symbol: Symbol): Type | undefined {
9004+ const links = getSymbolLinks(symbol);
9005+ return links.writeType || (links.writeType = getTypeOfAccessorsWorker(symbol, /*isWrite*/ true));
90019006 }
90029007
9003- function getTypeOfAccessorsWorker(symbol: Symbol): Type {
9008+ function getTypeOfAccessorsWorker(symbol: Symbol, writing = false ): Type | undefined {
90049009 if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
90059010 return errorType;
90069011 }
90079012
9008- let type = resolveTypeOfAccessors(symbol);
9013+ let type = resolveTypeOfAccessors(symbol, writing );
90099014
90109015 if (!popTypeResolution()) {
90119016 type = anyType;
@@ -9017,49 +9022,58 @@ namespace ts {
90179022 return type;
90189023 }
90199024
9020- function resolveTypeOfAccessors(symbol: Symbol) {
9025+ function resolveTypeOfAccessors(symbol: Symbol, writing = false ) {
90219026 const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
90229027 const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
90239028
9029+ // For write operations, prioritize type annotations on the setter
9030+ if (writing) {
9031+ const setterParameterType = getAnnotatedAccessorType(setter);
9032+ if (setterParameterType) {
9033+ return setterParameterType;
9034+ }
9035+ }
9036+ // Else defer to the getter type
9037+
90249038 if (getter && isInJSFile(getter)) {
90259039 const jsDocType = getTypeForDeclarationFromJSDocComment(getter);
90269040 if (jsDocType) {
90279041 return jsDocType;
90289042 }
90299043 }
9030- // First try to see if the user specified a return type on the get-accessor.
9044+
9045+ // Try to see if the user specified a return type on the get-accessor.
90319046 const getterReturnType = getAnnotatedAccessorType(getter);
90329047 if (getterReturnType) {
90339048 return getterReturnType;
90349049 }
9035- else {
9036- // If the user didn't specify a return type, try to use the set-accessor's parameter type.
9037- const setterParameterType = getAnnotatedAccessorType(setter);
9038- if (setterParameterType) {
9039- return setterParameterType;
9050+
9051+ // If the user didn't specify a return type, try to use the set-accessor's parameter type.
9052+ const setterParameterType = getAnnotatedAccessorType(setter);
9053+ if (setterParameterType) {
9054+ return setterParameterType;
9055+ }
9056+
9057+ // If there are no specified types, try to infer it from the body of the get accessor if it exists.
9058+ if (getter && getter.body) {
9059+ return getReturnTypeFromBody(getter);
9060+ }
9061+
9062+ // Otherwise, fall back to 'any'.
9063+ if (setter) {
9064+ if (!isPrivateWithinAmbient(setter)) {
9065+ errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
90409066 }
9041- else {
9042- // If there are no specified types, try to infer it from the body of the get accessor if it exists.
9043- if (getter && getter.body) {
9044- return getReturnTypeFromBody(getter);
9045- }
9046- // Otherwise, fall back to 'any'.
9047- else {
9048- if (setter) {
9049- if (!isPrivateWithinAmbient(setter)) {
9050- errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
9051- }
9052- }
9053- else {
9054- Debug.assert(!!getter, "there must exist a getter as we are current checking either setter or getter in this function");
9055- if (!isPrivateWithinAmbient(getter)) {
9056- errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
9057- }
9058- }
9059- return anyType;
9060- }
9067+ return anyType;
9068+ }
9069+ else if (getter) {
9070+ Debug.assert(!!getter, "there must exist a getter as we are current checking either setter or getter in this function");
9071+ if (!isPrivateWithinAmbient(getter)) {
9072+ errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
90619073 }
9074+ return anyType;
90629075 }
9076+ return undefined;
90639077 }
90649078
90659079 function getBaseTypeVariableOfClass(symbol: Symbol) {
@@ -9186,6 +9200,16 @@ namespace ts {
91869200 return links.type;
91879201 }
91889202
9203+ function getWriteTypeOfSymbol(symbol: Symbol): Type {
9204+ if (symbol.flags & SymbolFlags.Accessor) {
9205+ const type = getTypeOfSetAccessor(symbol);
9206+ if (type) {
9207+ return type;
9208+ }
9209+ }
9210+ return getTypeOfSymbol(symbol);
9211+ }
9212+
91899213 function getTypeOfSymbol(symbol: Symbol): Type {
91909214 const checkFlags = getCheckFlags(symbol);
91919215 if (checkFlags & CheckFlags.DeferredType) {
@@ -26550,8 +26574,8 @@ namespace ts {
2655026574 */
2655126575 function checkPropertyAccessibility(
2655226576 node: PropertyAccessExpression | QualifiedName | PropertyAccessExpression | VariableDeclaration | ParameterDeclaration | ImportTypeNode | PropertyAssignment | ShorthandPropertyAssignment | BindingElement,
26553- isSuper: boolean, type: Type, prop: Symbol): boolean {
26554- const flags = getDeclarationModifierFlagsFromSymbol(prop);
26577+ isSuper: boolean, type: Type, prop: Symbol, isWrite = false ): boolean {
26578+ const flags = getDeclarationModifierFlagsFromSymbol(prop, isWrite );
2655526579 const errorNode = node.kind === SyntaxKind.QualifiedName ? node.right :
2655626580 node.kind === SyntaxKind.ImportType ? node :
2655726581 node.kind === SyntaxKind.BindingElement && node.propertyName ? node.propertyName : node.name;
@@ -26870,7 +26894,7 @@ namespace ts {
2687026894 markAliasReferenced(parentSymbol, node);
2687126895 }
2687226896
26873- let propType: Type;
26897+ let propType: Type | undefined ;
2687426898 if (!prop) {
2687526899 const indexInfo = !isPrivateIdentifier(right) && (assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) || isThisTypeParameter(leftType)) ? getIndexInfoOfType(apparentType, IndexKind.String) : undefined;
2687626900 if (!(indexInfo && indexInfo.type)) {
@@ -26907,13 +26931,18 @@ namespace ts {
2690726931 checkPropertyNotUsedBeforeDeclaration(prop, node, right);
2690826932 markPropertyAsReferenced(prop, node, isSelfTypeAccess(left, parentSymbol));
2690926933 getNodeLinks(node).resolvedSymbol = prop;
26910- checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop);
26934+ const isWrite = isWriteAccess(node);
26935+ checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop, isWrite);
2691126936 if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) {
2691226937 error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
2691326938 return errorType;
2691426939 }
26915- propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : getTypeOfSymbol(prop);
26940+
26941+ if (propType === undefined) {
26942+ propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : isWrite ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop);
26943+ }
2691626944 }
26945+
2691726946 return getFlowTypeOfAccessExpression(node, prop, propType, right, checkMode);
2691826947 }
2691926948
@@ -32926,18 +32955,19 @@ namespace ts {
3292632955 const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
3292732956 const otherAccessor = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(node), otherKind);
3292832957 if (otherAccessor) {
32929- const nodeFlags = getEffectiveModifierFlags(node);
32930- const otherFlags = getEffectiveModifierFlags(otherAccessor);
32931- if ((nodeFlags & ModifierFlags.AccessibilityModifier) !== (otherFlags & ModifierFlags.AccessibilityModifier)) {
32932- error(node.name, Diagnostics.Getter_and_setter_accessors_do_not_agree_in_visibility);
32933- }
32934- if ((nodeFlags & ModifierFlags.Abstract) !== (otherFlags & ModifierFlags.Abstract)) {
32958+ const getter = node.kind === SyntaxKind.GetAccessor ? node : otherAccessor;
32959+ const setter = node.kind === SyntaxKind.SetAccessor ? node : otherAccessor;
32960+ const getterFlags = getEffectiveModifierFlags(getter);
32961+ const setterFlags = getEffectiveModifierFlags(setter);
32962+ if ((getterFlags & ModifierFlags.Abstract) !== (setterFlags & ModifierFlags.Abstract)) {
3293532963 error(node.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract);
3293632964 }
32965+ if (((getterFlags & ModifierFlags.Protected) && !(setterFlags & (ModifierFlags.Protected | ModifierFlags.Private))) ||
32966+ ((getterFlags & ModifierFlags.Private) && !(setterFlags & ModifierFlags.Private))) {
32967+ error(node.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter);
32968+ }
3293732969
32938- // TypeScript 1.0 spec (April 2014): 4.5
32939- // If both accessors include type annotations, the specified types must be identical.
32940- checkAccessorDeclarationTypesIdentical(node, otherAccessor, getAnnotatedAccessorType, Diagnostics.get_and_set_accessor_must_have_the_same_type);
32970+ checkAccessorDeclarationTypesAssignable(getter, setter, getAnnotatedAccessorType, Diagnostics.The_return_type_of_a_get_accessor_must_be_assignable_to_its_set_accessor_type);
3294132971 checkAccessorDeclarationTypesIdentical(node, otherAccessor, getThisTypeOfDeclaration, Diagnostics.get_and_set_accessor_must_have_the_same_this_type);
3294232972 }
3294332973 }
@@ -32950,9 +32980,17 @@ namespace ts {
3295032980 }
3295132981
3295232982 function checkAccessorDeclarationTypesIdentical(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type | undefined, message: DiagnosticMessage) {
32983+ return checkAccessorDeclarationTypesMatch(first, second, getAnnotatedType, isTypeIdenticalTo, message);
32984+ }
32985+
32986+ function checkAccessorDeclarationTypesAssignable(getter: AccessorDeclaration, setter: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type | undefined, message: DiagnosticMessage) {
32987+ return checkAccessorDeclarationTypesMatch(getter, setter, getAnnotatedType, isTypeAssignableTo, message);
32988+ }
32989+
32990+ function checkAccessorDeclarationTypesMatch(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type | undefined, match: typeof areTypesComparable, message: DiagnosticMessage) {
3295332991 const firstType = getAnnotatedType(first);
3295432992 const secondType = getAnnotatedType(second);
32955- if (firstType && secondType && !isTypeIdenticalTo (firstType, secondType)) {
32993+ if (firstType && secondType && !match (firstType, secondType)) {
3295632994 error(first, message);
3295732995 }
3295832996 }
@@ -40865,7 +40903,7 @@ namespace ts {
4086540903 }
4086640904
4086740905 function checkGrammarAccessor(accessor: AccessorDeclaration): boolean {
40868- if (!(accessor.flags & NodeFlags.Ambient)) {
40906+ if (!(accessor.flags & NodeFlags.Ambient) && (accessor.parent.kind !== SyntaxKind.TypeLiteral) && (accessor.parent.kind !== SyntaxKind.InterfaceDeclaration) ) {
4086940907 if (languageVersion < ScriptTarget.ES5) {
4087040908 return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher);
4087140909 }
0 commit comments