@@ -8723,7 +8723,7 @@ namespace ts {
8723
8723
return links.type;
8724
8724
}
8725
8725
8726
- function getTypeOfVariableOrParameterOrPropertyWorker(symbol: Symbol) {
8726
+ function getTypeOfVariableOrParameterOrPropertyWorker(symbol: Symbol): Type {
8727
8727
// Handle prototype property
8728
8728
if (symbol.flags & SymbolFlags.Prototype) {
8729
8729
return getTypeOfPrototypeProperty(symbol);
@@ -8763,7 +8763,7 @@ namespace ts {
8763
8763
}
8764
8764
return reportCircularityError(symbol);
8765
8765
}
8766
- let type: Type | undefined ;
8766
+ let type: Type;
8767
8767
if (declaration.kind === SyntaxKind.ExportAssignment) {
8768
8768
type = widenTypeForVariableLikeDeclaration(checkExpressionCached((<ExportAssignment>declaration).expression), declaration);
8769
8769
}
@@ -8820,7 +8820,7 @@ namespace ts {
8820
8820
type = getTypeOfEnumMember(symbol);
8821
8821
}
8822
8822
else if (isAccessor(declaration)) {
8823
- type = resolveTypeOfAccessors(symbol);
8823
+ type = resolveTypeOfAccessors(symbol) || Debug.fail("Non-write accessor resolution must always produce a type") ;
8824
8824
}
8825
8825
else {
8826
8826
return Debug.fail("Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + Debug.formatSymbol(symbol));
@@ -8866,15 +8866,20 @@ namespace ts {
8866
8866
8867
8867
function getTypeOfAccessors(symbol: Symbol): Type {
8868
8868
const links = getSymbolLinks(symbol);
8869
- return links.type || (links.type = getTypeOfAccessorsWorker(symbol));
8869
+ return links.type || (links.type = getTypeOfAccessorsWorker(symbol) || Debug.fail("Read type of accessor must always produce a type"));
8870
+ }
8871
+
8872
+ function getTypeOfSetAccessor(symbol: Symbol): Type | undefined {
8873
+ const links = getSymbolLinks(symbol);
8874
+ return links.writeType || (links.writeType = getTypeOfAccessorsWorker(symbol, /*isWrite*/ true));
8870
8875
}
8871
8876
8872
- function getTypeOfAccessorsWorker(symbol: Symbol): Type {
8877
+ function getTypeOfAccessorsWorker(symbol: Symbol, writing = false ): Type | undefined {
8873
8878
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
8874
8879
return errorType;
8875
8880
}
8876
8881
8877
- let type = resolveTypeOfAccessors(symbol);
8882
+ let type = resolveTypeOfAccessors(symbol, writing );
8878
8883
8879
8884
if (!popTypeResolution()) {
8880
8885
type = anyType;
@@ -8886,49 +8891,58 @@ namespace ts {
8886
8891
return type;
8887
8892
}
8888
8893
8889
- function resolveTypeOfAccessors(symbol: Symbol) {
8894
+ function resolveTypeOfAccessors(symbol: Symbol, writing = false ) {
8890
8895
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
8891
8896
const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
8892
8897
8898
+ // For write operations, prioritize type annotations on the setter
8899
+ if (writing) {
8900
+ const setterParameterType = getAnnotatedAccessorType(setter);
8901
+ if (setterParameterType) {
8902
+ return setterParameterType;
8903
+ }
8904
+ }
8905
+ // Else defer to the getter type
8906
+
8893
8907
if (getter && isInJSFile(getter)) {
8894
8908
const jsDocType = getTypeForDeclarationFromJSDocComment(getter);
8895
8909
if (jsDocType) {
8896
8910
return jsDocType;
8897
8911
}
8898
8912
}
8899
- // First try to see if the user specified a return type on the get-accessor.
8913
+
8914
+ // Try to see if the user specified a return type on the get-accessor.
8900
8915
const getterReturnType = getAnnotatedAccessorType(getter);
8901
8916
if (getterReturnType) {
8902
8917
return getterReturnType;
8903
8918
}
8904
- else {
8905
- // If the user didn't specify a return type, try to use the set-accessor's parameter type.
8906
- const setterParameterType = getAnnotatedAccessorType(setter);
8907
- if (setterParameterType) {
8908
- return setterParameterType;
8919
+
8920
+ // If the user didn't specify a return type, try to use the set-accessor's parameter type.
8921
+ const setterParameterType = getAnnotatedAccessorType(setter);
8922
+ if (setterParameterType) {
8923
+ return setterParameterType;
8924
+ }
8925
+
8926
+ // If there are no specified types, try to infer it from the body of the get accessor if it exists.
8927
+ if (getter && getter.body) {
8928
+ return getReturnTypeFromBody(getter);
8929
+ }
8930
+
8931
+ // Otherwise, fall back to 'any'.
8932
+ if (setter) {
8933
+ if (!isPrivateWithinAmbient(setter)) {
8934
+ errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
8909
8935
}
8910
- else {
8911
- // If there are no specified types, try to infer it from the body of the get accessor if it exists.
8912
- if (getter && getter.body) {
8913
- return getReturnTypeFromBody(getter);
8914
- }
8915
- // Otherwise, fall back to 'any'.
8916
- else {
8917
- if (setter) {
8918
- if (!isPrivateWithinAmbient(setter)) {
8919
- errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
8920
- }
8921
- }
8922
- else {
8923
- Debug.assert(!!getter, "there must exist a getter as we are current checking either setter or getter in this function");
8924
- if (!isPrivateWithinAmbient(getter)) {
8925
- errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
8926
- }
8927
- }
8928
- return anyType;
8929
- }
8936
+ return anyType;
8937
+ }
8938
+ else if (getter) {
8939
+ Debug.assert(!!getter, "there must exist a getter as we are current checking either setter or getter in this function");
8940
+ if (!isPrivateWithinAmbient(getter)) {
8941
+ errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
8930
8942
}
8943
+ return anyType;
8931
8944
}
8945
+ return undefined;
8932
8946
}
8933
8947
8934
8948
function getBaseTypeVariableOfClass(symbol: Symbol) {
@@ -9055,6 +9069,16 @@ namespace ts {
9055
9069
return links.type;
9056
9070
}
9057
9071
9072
+ function getWriteTypeOfSymbol(symbol: Symbol): Type {
9073
+ if (symbol.flags & SymbolFlags.Accessor) {
9074
+ const type = getTypeOfSetAccessor(symbol);
9075
+ if (type) {
9076
+ return type;
9077
+ }
9078
+ }
9079
+ return getTypeOfSymbol(symbol);
9080
+ }
9081
+
9058
9082
function getTypeOfSymbol(symbol: Symbol): Type {
9059
9083
const checkFlags = getCheckFlags(symbol);
9060
9084
if (checkFlags & CheckFlags.DeferredType) {
@@ -25968,17 +25992,9 @@ namespace ts {
25968
25992
function checkPropertyAccessibility(
25969
25993
node: PropertyAccessExpression | QualifiedName | PropertyAccessExpression | VariableDeclaration | ParameterDeclaration | ImportTypeNode | PropertyAssignment | ShorthandPropertyAssignment | BindingElement,
25970
25994
isSuper: boolean, type: Type, prop: Symbol, isWrite = false): boolean {
25971
- let flags = getDeclarationModifierFlagsFromSymbol(prop);
25995
+ const flags = getDeclarationModifierFlagsFromSymbol(prop, isWrite );
25972
25996
const errorNode = node.kind === SyntaxKind.QualifiedName ? node.right : node.kind === SyntaxKind.ImportType ? node : node.name;
25973
25997
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
-
25982
25998
if (isSuper) {
25983
25999
// TS 1.0 spec (April 2014): 4.8.2
25984
26000
// - In a constructor, instance member function, instance member accessor, or
@@ -26336,15 +26352,9 @@ namespace ts {
26336
26352
error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
26337
26353
return errorType;
26338
26354
}
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
26355
26346
26356
if (propType === undefined) {
26347
- propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : getConstraintForLocation(getTypeOfSymbol(prop), node);
26357
+ propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : getConstraintForLocation(isWrite ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop), node);
26348
26358
}
26349
26359
}
26350
26360
// For writes to properties declared as accessors, use the 'set' type
0 commit comments