@@ -8844,7 +8844,7 @@ namespace ts {
8844
8844
return links.type;
8845
8845
}
8846
8846
8847
- function getTypeOfVariableOrParameterOrPropertyWorker(symbol: Symbol) {
8847
+ function getTypeOfVariableOrParameterOrPropertyWorker(symbol: Symbol): Type {
8848
8848
// Handle prototype property
8849
8849
if (symbol.flags & SymbolFlags.Prototype) {
8850
8850
return getTypeOfPrototypeProperty(symbol);
@@ -8894,7 +8894,7 @@ namespace ts {
8894
8894
}
8895
8895
return reportCircularityError(symbol);
8896
8896
}
8897
- let type: Type | undefined ;
8897
+ let type: Type;
8898
8898
if (declaration.kind === SyntaxKind.ExportAssignment) {
8899
8899
type = widenTypeForVariableLikeDeclaration(checkExpressionCached((<ExportAssignment>declaration).expression), declaration);
8900
8900
}
@@ -8951,7 +8951,7 @@ namespace ts {
8951
8951
type = getTypeOfEnumMember(symbol);
8952
8952
}
8953
8953
else if (isAccessor(declaration)) {
8954
- type = resolveTypeOfAccessors(symbol);
8954
+ type = resolveTypeOfAccessors(symbol) || Debug.fail("Non-write accessor resolution must always produce a type") ;
8955
8955
}
8956
8956
else {
8957
8957
return Debug.fail("Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + Debug.formatSymbol(symbol));
@@ -8997,15 +8997,20 @@ namespace ts {
8997
8997
8998
8998
function getTypeOfAccessors(symbol: Symbol): Type {
8999
8999
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));
9001
9006
}
9002
9007
9003
- function getTypeOfAccessorsWorker(symbol: Symbol): Type {
9008
+ function getTypeOfAccessorsWorker(symbol: Symbol, writing = false ): Type | undefined {
9004
9009
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
9005
9010
return errorType;
9006
9011
}
9007
9012
9008
- let type = resolveTypeOfAccessors(symbol);
9013
+ let type = resolveTypeOfAccessors(symbol, writing );
9009
9014
9010
9015
if (!popTypeResolution()) {
9011
9016
type = anyType;
@@ -9017,49 +9022,58 @@ namespace ts {
9017
9022
return type;
9018
9023
}
9019
9024
9020
- function resolveTypeOfAccessors(symbol: Symbol) {
9025
+ function resolveTypeOfAccessors(symbol: Symbol, writing = false ) {
9021
9026
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
9022
9027
const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
9023
9028
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
+
9024
9038
if (getter && isInJSFile(getter)) {
9025
9039
const jsDocType = getTypeForDeclarationFromJSDocComment(getter);
9026
9040
if (jsDocType) {
9027
9041
return jsDocType;
9028
9042
}
9029
9043
}
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.
9031
9046
const getterReturnType = getAnnotatedAccessorType(getter);
9032
9047
if (getterReturnType) {
9033
9048
return getterReturnType;
9034
9049
}
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));
9040
9066
}
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));
9061
9073
}
9074
+ return anyType;
9062
9075
}
9076
+ return undefined;
9063
9077
}
9064
9078
9065
9079
function getBaseTypeVariableOfClass(symbol: Symbol) {
@@ -9186,6 +9200,16 @@ namespace ts {
9186
9200
return links.type;
9187
9201
}
9188
9202
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
+
9189
9213
function getTypeOfSymbol(symbol: Symbol): Type {
9190
9214
const checkFlags = getCheckFlags(symbol);
9191
9215
if (checkFlags & CheckFlags.DeferredType) {
@@ -26550,8 +26574,8 @@ namespace ts {
26550
26574
*/
26551
26575
function checkPropertyAccessibility(
26552
26576
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 );
26555
26579
const errorNode = node.kind === SyntaxKind.QualifiedName ? node.right :
26556
26580
node.kind === SyntaxKind.ImportType ? node :
26557
26581
node.kind === SyntaxKind.BindingElement && node.propertyName ? node.propertyName : node.name;
@@ -26870,7 +26894,7 @@ namespace ts {
26870
26894
markAliasReferenced(parentSymbol, node);
26871
26895
}
26872
26896
26873
- let propType: Type;
26897
+ let propType: Type | undefined ;
26874
26898
if (!prop) {
26875
26899
const indexInfo = !isPrivateIdentifier(right) && (assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) || isThisTypeParameter(leftType)) ? getIndexInfoOfType(apparentType, IndexKind.String) : undefined;
26876
26900
if (!(indexInfo && indexInfo.type)) {
@@ -26907,13 +26931,18 @@ namespace ts {
26907
26931
checkPropertyNotUsedBeforeDeclaration(prop, node, right);
26908
26932
markPropertyAsReferenced(prop, node, isSelfTypeAccess(left, parentSymbol));
26909
26933
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);
26911
26936
if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) {
26912
26937
error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right));
26913
26938
return errorType;
26914
26939
}
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
+ }
26916
26944
}
26945
+
26917
26946
return getFlowTypeOfAccessExpression(node, prop, propType, right, checkMode);
26918
26947
}
26919
26948
@@ -32926,18 +32955,19 @@ namespace ts {
32926
32955
const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
32927
32956
const otherAccessor = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(node), otherKind);
32928
32957
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)) {
32935
32963
error(node.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract);
32936
32964
}
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
+ }
32937
32969
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);
32941
32971
checkAccessorDeclarationTypesIdentical(node, otherAccessor, getThisTypeOfDeclaration, Diagnostics.get_and_set_accessor_must_have_the_same_this_type);
32942
32972
}
32943
32973
}
@@ -32950,9 +32980,17 @@ namespace ts {
32950
32980
}
32951
32981
32952
32982
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) {
32953
32991
const firstType = getAnnotatedType(first);
32954
32992
const secondType = getAnnotatedType(second);
32955
- if (firstType && secondType && !isTypeIdenticalTo (firstType, secondType)) {
32993
+ if (firstType && secondType && !match (firstType, secondType)) {
32956
32994
error(first, message);
32957
32995
}
32958
32996
}
@@ -40865,7 +40903,7 @@ namespace ts {
40865
40903
}
40866
40904
40867
40905
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) ) {
40869
40907
if (languageVersion < ScriptTarget.ES5) {
40870
40908
return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher);
40871
40909
}
0 commit comments