@@ -25967,10 +25967,18 @@ namespace ts {
2596725967 */
2596825968 function checkPropertyAccessibility(
2596925969 node: PropertyAccessExpression | QualifiedName | PropertyAccessExpression | VariableDeclaration | ParameterDeclaration | ImportTypeNode | PropertyAssignment | ShorthandPropertyAssignment | BindingElement,
25970- isSuper: boolean, type: Type, prop: Symbol): boolean {
25971- const flags = getDeclarationModifierFlagsFromSymbol(prop);
25970+ isSuper: boolean, type: Type, prop: Symbol, isWrite = false ): boolean {
25971+ let flags = getDeclarationModifierFlagsFromSymbol(prop);
2597225972 const errorNode = node.kind === SyntaxKind.QualifiedName ? node.right : node.kind === SyntaxKind.ImportType ? node : node.name;
2597325973
25974+ // Writes use the visibility modifier of the set accessor, if one is declared
25975+ if (isWrite) {
25976+ const setter = forEach(prop.declarations, p => p.kind === SyntaxKind.SetAccessor && p);
25977+ if (setter) {
25978+ flags = (flags & ~ModifierFlags.AccessibilityModifier) | getEffectiveDeclarationFlags(setter, ModifierFlags.AccessibilityModifier);
25979+ }
25980+ }
25981+
2597425982 if (isSuper) {
2597525983 // TS 1.0 spec (April 2014): 4.8.2
2597625984 // - In a constructor, instance member function, instance member accessor, or
@@ -26285,7 +26293,7 @@ namespace ts {
2628526293 markAliasReferenced(parentSymbol, node);
2628626294 }
2628726295
26288- let propType: Type;
26296+ let propType: Type | undefined ;
2628926297 if (!prop) {
2629026298 const indexInfo = !isPrivateIdentifier(right) && (assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) || isThisTypeParameter(leftType)) ? getIndexInfoOfType(apparentType, IndexKind.String) : undefined;
2629126299 if (!(indexInfo && indexInfo.type)) {
@@ -26316,19 +26324,30 @@ namespace ts {
2631626324 }
2631726325 }
2631826326 else {
26327+ const isWrite = isWriteAccess(node);
2631926328 if (getDeclarationNodeFlagsFromSymbol(prop) & NodeFlags.Deprecated && isUncalledFunctionReference(node, prop)) {
2632026329 errorOrSuggestion(/* isError */ false, right, Diagnostics._0_is_deprecated, right.escapedText as string);
2632126330 }
2632226331 checkPropertyNotUsedBeforeDeclaration(prop, node, right);
2632326332 markPropertyAsReferenced(prop, node, left.kind === SyntaxKind.ThisKeyword);
2632426333 getNodeLinks(node).resolvedSymbol = prop;
26325- checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop);
26334+ checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop, isWrite );
2632626335 if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) {
2632726336 error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
2632826337 return errorType;
2632926338 }
26330- propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : getConstraintForLocation(getTypeOfSymbol(prop), node);
26339+ if (isWrite) {
26340+ const setter = forEach(prop.declarations, p => (p.kind === SyntaxKind.SetAccessor && p));
26341+ if (setter) {
26342+ propType = getAnnotatedAccessorType(setter as SetAccessorDeclaration);
26343+ }
26344+ }
26345+
26346+ if (propType === undefined) {
26347+ propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : getConstraintForLocation(getTypeOfSymbol(prop), node);
26348+ }
2633126349 }
26350+ // For writes to properties declared as accessors, use the 'set' type
2633226351 return getFlowTypeOfAccessExpression(node, prop, propType, right);
2633326352 }
2633426353
@@ -32321,15 +32340,19 @@ namespace ts {
3232132340 const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
3232232341 const otherAccessor = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(node), otherKind);
3232332342 if (otherAccessor) {
32324- const nodeFlags = getEffectiveModifierFlags(node);
32325- const otherFlags = getEffectiveModifierFlags(otherAccessor);
32326- if ((nodeFlags & ModifierFlags.Abstract) !== (otherFlags & ModifierFlags.Abstract)) {
32343+ const getter = node.kind === SyntaxKind.GetAccessor ? node : otherAccessor;
32344+ const setter = node.kind === SyntaxKind.SetAccessor ? node : otherAccessor;
32345+ const getterFlags = getEffectiveModifierFlags(getter);
32346+ const setterFlags = getEffectiveModifierFlags(setter);
32347+ if ((getterFlags & ModifierFlags.Abstract) !== (setterFlags & ModifierFlags.Abstract)) {
3232732348 error(node.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract);
3232832349 }
32350+ if (((getterFlags & ModifierFlags.Protected) && !(setterFlags & (ModifierFlags.Protected | ModifierFlags.Private))) ||
32351+ ((getterFlags & ModifierFlags.Private) && !(setterFlags & ModifierFlags.Private))) {
32352+ error(node.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter);
32353+ }
3232932354
32330- // TypeScript 1.0 spec (April 2014): 4.5
32331- // If both accessors include type annotations, the specified types must be identical.
32332- checkAccessorDeclarationTypesAssignable(node, otherAccessor, getAnnotatedAccessorType, Diagnostics.get_and_set_accessor_must_have_the_comparable_types);
32355+ checkAccessorDeclarationTypesAssignable(getter, setter, getAnnotatedAccessorType, Diagnostics.The_return_type_of_a_get_accessor_must_be_assignable_to_its_set_accessor_type);
3233332356 checkAccessorDeclarationTypesIdentical(node, otherAccessor, getThisTypeOfDeclaration, Diagnostics.get_and_set_accessor_must_have_the_same_this_type);
3233432357 }
3233532358 }
@@ -32345,8 +32368,8 @@ namespace ts {
3234532368 return checkAccessorDeclarationTypesMatch(first, second, getAnnotatedType, isTypeIdenticalTo, message);
3234632369 }
3234732370
32348- function checkAccessorDeclarationTypesAssignable(first : AccessorDeclaration, second : AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type | undefined, message: DiagnosticMessage) {
32349- return checkAccessorDeclarationTypesMatch(first, second , getAnnotatedType, areTypesComparable , message);
32371+ function checkAccessorDeclarationTypesAssignable(getter : AccessorDeclaration, setter : AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type | undefined, message: DiagnosticMessage) {
32372+ return checkAccessorDeclarationTypesMatch(getter, setter , getAnnotatedType, isTypeAssignableTo , message);
3235032373 }
3235132374
3235232375 function checkAccessorDeclarationTypesMatch(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type | undefined, match: typeof areTypesComparable, message: DiagnosticMessage) {
@@ -32357,7 +32380,6 @@ namespace ts {
3235732380 }
3235832381 }
3235932382
32360-
3236132383 function checkMissingDeclaration(node: Node) {
3236232384 checkDecorators(node);
3236332385 }
@@ -40171,7 +40193,7 @@ namespace ts {
4017140193 }
4017240194
4017340195 function checkGrammarAccessor(accessor: AccessorDeclaration): boolean {
40174- if (!(accessor.flags & NodeFlags.Ambient)) {
40196+ if (!(accessor.flags & NodeFlags.Ambient) && (accessor.parent.kind !== SyntaxKind.TypeLiteral) && (accessor.parent.kind !== SyntaxKind.InterfaceDeclaration) ) {
4017540197 if (languageVersion < ScriptTarget.ES5) {
4017640198 return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher);
4017740199 }
0 commit comments