@@ -172,6 +172,7 @@ namespace ts {
172
172
EnumTagType,
173
173
ResolvedTypeArguments,
174
174
ResolvedBaseTypes,
175
+ WriteType,
175
176
}
176
177
177
178
const enum CheckMode {
@@ -8519,6 +8520,8 @@ namespace ts {
8519
8520
return !!(target as TypeReference).resolvedTypeArguments;
8520
8521
case TypeSystemPropertyName.ResolvedBaseTypes:
8521
8522
return !!(target as InterfaceType).baseTypesResolved;
8523
+ case TypeSystemPropertyName.WriteType:
8524
+ return !!getSymbolLinks(target as Symbol).writeType;
8522
8525
}
8523
8526
return Debug.assertNever(propertyName);
8524
8527
}
@@ -9502,6 +9505,11 @@ namespace ts {
9502
9505
}
9503
9506
return getWidenedType(getWidenedLiteralType(checkExpression(declaration.statements[0].expression)));
9504
9507
}
9508
+ if (isAccessor(declaration)) {
9509
+ // Binding of certain patterns in JS code will occasionally mark symbols as both properties
9510
+ // and accessors. Here we dispatch to accessor resolution if needed.
9511
+ return getTypeOfAccessors(symbol);
9512
+ }
9505
9513
9506
9514
// Handle variable, parameter or property
9507
9515
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
@@ -9567,9 +9575,6 @@ namespace ts {
9567
9575
else if (isEnumMember(declaration)) {
9568
9576
type = getTypeOfEnumMember(symbol);
9569
9577
}
9570
- else if (isAccessor(declaration)) {
9571
- type = resolveTypeOfAccessors(symbol) || Debug.fail("Non-write accessor resolution must always produce a type");
9572
- }
9573
9578
else {
9574
9579
return Debug.fail("Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + Debug.formatSymbol(symbol));
9575
9580
}
@@ -9614,97 +9619,62 @@ namespace ts {
9614
9619
9615
9620
function getTypeOfAccessors(symbol: Symbol): Type {
9616
9621
const links = getSymbolLinks(symbol);
9617
- return links.type || (links.type = getTypeOfAccessorsWorker(symbol) || Debug.fail("Read type of accessor must always produce a type"));
9618
- }
9619
-
9620
- function getTypeOfSetAccessor(symbol: Symbol): Type | undefined {
9621
- const links = getSymbolLinks(symbol);
9622
- return links.writeType || (links.writeType = getTypeOfAccessorsWorker(symbol, /*writing*/ true));
9623
- }
9624
-
9625
- function getTypeOfAccessorsWorker(symbol: Symbol, writing = false): Type | undefined {
9626
- if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
9627
- return errorType;
9628
- }
9629
-
9630
- let type = resolveTypeOfAccessors(symbol, writing);
9631
- if (!popTypeResolution()) {
9622
+ if (!links.type) {
9623
+ if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
9624
+ return errorType;
9625
+ }
9632
9626
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
9633
- if (getter) {
9634
- if (getEffectiveTypeAnnotationNode(getter)) {
9635
- error(getter.name, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol));
9627
+ const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
9628
+ // We try to resolve a getter type annotation, a setter type annotation, or a getter function
9629
+ // body return type inference, in that order.
9630
+ let type = getter && isInJSFile(getter) && getTypeForDeclarationFromJSDocComment(getter) ||
9631
+ getAnnotatedAccessorType(getter) ||
9632
+ getAnnotatedAccessorType(setter) ||
9633
+ getter && getter.body && getReturnTypeFromBody(getter);
9634
+ if (!type) {
9635
+ if (setter && !isPrivateWithinAmbient(setter)) {
9636
+ errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
9637
+ }
9638
+ else if (getter && !isPrivateWithinAmbient(getter)) {
9639
+ errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
9640
+ }
9641
+ type = anyType;
9642
+ }
9643
+ if (!popTypeResolution()) {
9644
+ if (getAnnotatedAccessorTypeNode(getter)) {
9645
+ error(getter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol));
9636
9646
}
9637
- else if (noImplicitAny) {
9647
+ else if (getAnnotatedAccessorTypeNode(setter)) {
9648
+ error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol));
9649
+ }
9650
+ else if (getter && noImplicitAny) {
9638
9651
error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol));
9639
9652
}
9653
+ type = anyType;
9640
9654
}
9641
- type = anyType ;
9655
+ links. type = type ;
9642
9656
}
9643
- return type;
9657
+ return links. type;
9644
9658
}
9645
9659
9646
- function resolveTypeOfAccessors(symbol: Symbol, writing = false) {
9647
- const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
9648
- const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
9649
-
9650
- // For write operations, prioritize type annotations on the setter
9651
- if (writing) {
9652
- const setterType = getAnnotatedAccessorType(setter);
9653
- if (setterType) {
9654
- return instantiateTypeIfNeeded(setterType, symbol);
9655
- }
9656
- }
9657
- // Else defer to the getter type
9658
-
9659
- if (getter && isInJSFile(getter)) {
9660
- const jsDocType = getTypeForDeclarationFromJSDocComment(getter);
9661
- if (jsDocType) {
9662
- return instantiateTypeIfNeeded(jsDocType, symbol);
9663
- }
9664
- }
9665
-
9666
- // Try to see if the user specified a return type on the get-accessor.
9667
- const getterType = getAnnotatedAccessorType(getter);
9668
- if (getterType) {
9669
- return instantiateTypeIfNeeded(getterType, symbol);
9670
- }
9671
-
9672
- // If the user didn't specify a return type, try to use the set-accessor's parameter type.
9673
- const setterType = getAnnotatedAccessorType(setter);
9674
- if (setterType) {
9675
- return setterType;
9676
- }
9677
-
9678
- // If there are no specified types, try to infer it from the body of the get accessor if it exists.
9679
- if (getter && getter.body) {
9680
- const returnTypeFromBody = getReturnTypeFromBody(getter);
9681
- return instantiateTypeIfNeeded(returnTypeFromBody, symbol);
9682
- }
9683
-
9684
- // Otherwise, fall back to 'any'.
9685
- if (setter) {
9686
- if (!isPrivateWithinAmbient(setter)) {
9687
- errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
9688
- }
9689
- return anyType;
9690
- }
9691
- else if (getter) {
9692
- Debug.assert(!!getter, "there must exist a getter as we are current checking either setter or getter in this function");
9693
- if (!isPrivateWithinAmbient(getter)) {
9694
- errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
9660
+ function getWriteTypeOfAccessors(symbol: Symbol): Type {
9661
+ const links = getSymbolLinks(symbol);
9662
+ if (!links.writeType) {
9663
+ if (!pushTypeResolution(symbol, TypeSystemPropertyName.WriteType)) {
9664
+ return errorType;
9695
9665
}
9696
- return anyType;
9697
- }
9698
- return undefined;
9699
-
9700
- function instantiateTypeIfNeeded(type: Type, symbol: Symbol) {
9701
- if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
9702
- const links = getSymbolLinks(symbol);
9703
- return instantiateType(type, links.mapper);
9666
+ const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
9667
+ let writeType = getAnnotatedAccessorType(setter);
9668
+ if (!popTypeResolution()) {
9669
+ if (getAnnotatedAccessorTypeNode(setter)) {
9670
+ error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol));
9671
+ }
9672
+ writeType = anyType;
9704
9673
}
9705
-
9706
- return type ;
9674
+ // Absent an explicit setter type annotation we use the read type of the accessor.
9675
+ links.writeType = writeType || getTypeOfAccessors(symbol) ;
9707
9676
}
9677
+ return links.writeType;
9708
9678
}
9709
9679
9710
9680
function getBaseTypeVariableOfClass(symbol: Symbol) {
@@ -9792,17 +9762,12 @@ namespace ts {
9792
9762
9793
9763
function getTypeOfInstantiatedSymbol(symbol: Symbol): Type {
9794
9764
const links = getSymbolLinks(symbol);
9795
- if (!links.type) {
9796
- if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
9797
- return links.type = errorType;
9798
- }
9799
- let type = instantiateType(getTypeOfSymbol(links.target!), links.mapper);
9800
- if (!popTypeResolution()) {
9801
- type = reportCircularityError(symbol);
9802
- }
9803
- links.type = type;
9804
- }
9805
- return links.type;
9765
+ return links.type || (links.type = instantiateType(getTypeOfSymbol(links.target!), links.mapper));
9766
+ }
9767
+
9768
+ function getWriteTypeOfInstantiatedSymbol(symbol: Symbol): Type {
9769
+ const links = getSymbolLinks(symbol);
9770
+ return links.writeType || (links.writeType = instantiateType(getWriteTypeOfSymbol(links.target!), links.mapper));
9806
9771
}
9807
9772
9808
9773
function reportCircularityError(symbol: Symbol) {
@@ -9845,36 +9810,23 @@ namespace ts {
9845
9810
}
9846
9811
9847
9812
/**
9848
- * Distinct write types come only from set accessors, but union and intersection
9849
- * properties deriving from set accessors will either pre-compute or defer the
9850
- * union or intersection of the writeTypes of their constituents. To account for
9851
- * this, we will assume that any deferred type or transient symbol may have a
9852
- * `writeType` (or a deferred write type ready to be computed) that should be
9853
- * used before looking for set accessor declarations.
9813
+ * Distinct write types come only from set accessors, but synthetic union and intersection
9814
+ * properties deriving from set accessors will either pre-compute or defer the union or
9815
+ * intersection of the writeTypes of their constituents.
9854
9816
*/
9855
9817
function getWriteTypeOfSymbol(symbol: Symbol): Type {
9856
9818
const checkFlags = getCheckFlags(symbol);
9857
- if (checkFlags & CheckFlags.DeferredType) {
9858
- const writeType = getWriteTypeOfSymbolWithDeferredType(symbol);
9859
- if (writeType) {
9860
- return writeType;
9861
- }
9862
- }
9863
- if (symbol.flags & SymbolFlags.Transient) {
9864
- const { writeType } = symbol as TransientSymbol;
9865
- if (writeType) {
9866
- return writeType;
9867
- }
9819
+ if (symbol.flags & SymbolFlags.Property) {
9820
+ return checkFlags & CheckFlags.SyntheticProperty ?
9821
+ checkFlags & CheckFlags.DeferredType ?
9822
+ getWriteTypeOfSymbolWithDeferredType(symbol) || getTypeOfSymbolWithDeferredType(symbol) :
9823
+ (symbol as TransientSymbol).writeType || (symbol as TransientSymbol).type! :
9824
+ getTypeOfSymbol(symbol);
9868
9825
}
9869
- return getSetAccessorTypeOfSymbol(symbol);
9870
- }
9871
-
9872
- function getSetAccessorTypeOfSymbol(symbol: Symbol): Type {
9873
9826
if (symbol.flags & SymbolFlags.Accessor) {
9874
- const type = getTypeOfSetAccessor(symbol);
9875
- if (type) {
9876
- return type;
9877
- }
9827
+ return checkFlags & CheckFlags.Instantiated ?
9828
+ getWriteTypeOfInstantiatedSymbol(symbol) :
9829
+ getWriteTypeOfAccessors(symbol);
9878
9830
}
9879
9831
return getTypeOfSymbol(symbol);
9880
9832
}
@@ -25237,7 +25189,7 @@ namespace ts {
25237
25189
}
25238
25190
}
25239
25191
if (isDeclarationName(location) && isSetAccessor(location.parent) && getAnnotatedAccessorTypeNode(location.parent)) {
25240
- return resolveTypeOfAccessors (location.parent.symbol, /*writing*/ true)! ;
25192
+ return getWriteTypeOfAccessors (location.parent.symbol) ;
25241
25193
}
25242
25194
// The location isn't a reference to the given symbol, meaning we're being asked
25243
25195
// a hypothetical question of what type the symbol would have if there was a reference
0 commit comments