@@ -4696,6 +4696,12 @@ namespace ts {
4696
4696
return addOptionality(type, isOptional);
4697
4697
}
4698
4698
}
4699
+ else if (isInJavaScriptFile(declaration)) {
4700
+ const expandoType = getJSExpandoObjectType(declaration, getSymbolOfNode(declaration), getDeclaredJavascriptInitializer(declaration));
4701
+ if (expandoType) {
4702
+ return expandoType;
4703
+ }
4704
+ }
4699
4705
4700
4706
// Use the type of the initializer expression if one is present
4701
4707
if (declaration.initializer) {
@@ -4718,15 +4724,16 @@ namespace ts {
4718
4724
return undefined;
4719
4725
}
4720
4726
4721
- function getWidenedTypeFromJSSpecialPropertyDeclarations (symbol: Symbol, resolvedSymbol?: Symbol) {
4727
+ function getWidenedTypeFromJSPropertyAssignments (symbol: Symbol, resolvedSymbol?: Symbol) {
4722
4728
// function/class/{} assignments are fresh declarations, not property assignments, so only add prototype assignments
4723
4729
const specialDeclaration = getAssignedJavascriptInitializer(symbol.valueDeclaration);
4724
4730
if (specialDeclaration) {
4725
4731
const tag = getJSDocTypeTag(specialDeclaration);
4726
4732
if (tag && tag.typeExpression) {
4727
4733
return getTypeFromTypeNode(tag.typeExpression);
4728
4734
}
4729
- return getWidenedLiteralType(checkExpressionCached(specialDeclaration));
4735
+ const expando = getJSExpandoObjectType(symbol.valueDeclaration, symbol, specialDeclaration);
4736
+ return expando || getWidenedLiteralType(checkExpressionCached(specialDeclaration));
4730
4737
}
4731
4738
let definedInConstructor = false;
4732
4739
let definedInMethod = false;
@@ -4778,6 +4785,27 @@ namespace ts {
4778
4785
return widened;
4779
4786
}
4780
4787
4788
+ function getJSExpandoObjectType(decl: Node, symbol: Symbol, init: Expression | undefined): Type | undefined {
4789
+ if (!init || !isObjectLiteralExpression(init) || init.properties.length) {
4790
+ return undefined;
4791
+ }
4792
+ const exports = createSymbolTable();
4793
+ while (isBinaryExpression(decl) || isPropertyAccessExpression(decl)) {
4794
+ const s = getSymbolOfNode(decl);
4795
+ if (s && hasEntries(s.exports)) {
4796
+ mergeSymbolTable(exports, s.exports);
4797
+ }
4798
+ decl = isBinaryExpression(decl) ? decl.parent : decl.parent.parent;
4799
+ }
4800
+ const s = getSymbolOfNode(decl);
4801
+ if (s && hasEntries(s.exports)) {
4802
+ mergeSymbolTable(exports, s.exports);
4803
+ }
4804
+ const type = createAnonymousType(symbol, exports, emptyArray, emptyArray, undefined, undefined);
4805
+ type.objectFlags |= ObjectFlags.JSLiteral;
4806
+ return type;
4807
+ }
4808
+
4781
4809
function getJSDocTypeFromSpecialDeclarations(declaredType: Type | undefined, expression: Expression, _symbol: Symbol, declaration: Declaration) {
4782
4810
const typeNode = getJSDocType(expression.parent);
4783
4811
if (typeNode) {
@@ -5041,98 +5069,51 @@ namespace ts {
5041
5069
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
5042
5070
return errorType;
5043
5071
}
5044
- let type = getJSSpecialType(symbol, declaration);
5045
- if (!type) {
5046
- if (isJSDocPropertyLikeTag(declaration)
5047
- || isPropertyAccessExpression(declaration)
5048
- || isIdentifier(declaration)
5049
- || isClassDeclaration(declaration)
5050
- || isFunctionDeclaration(declaration)
5051
- || (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration))
5052
- || isMethodSignature(declaration)) {
5053
- // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty`
5054
- if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
5055
- return getTypeOfFuncClassEnumModule(symbol);
5056
- }
5057
- type = tryGetTypeFromEffectiveTypeNode(declaration) || anyType;
5058
- }
5059
- else if (isPropertyAssignment(declaration)) {
5060
- type = tryGetTypeFromEffectiveTypeNode(declaration) || checkPropertyAssignment(declaration);
5061
- }
5062
- else if (isJsxAttribute(declaration)) {
5063
- type = tryGetTypeFromEffectiveTypeNode(declaration) || checkJsxAttribute(declaration);
5064
- }
5065
- else if (isShorthandPropertyAssignment(declaration)) {
5066
- type = tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionForMutableLocation(declaration.name, CheckMode.Normal);
5067
- }
5068
- else if (isObjectLiteralMethod(declaration)) {
5069
- type = tryGetTypeFromEffectiveTypeNode(declaration) || checkObjectLiteralMethod(declaration, CheckMode.Normal);
5070
- }
5071
- else if (isParameter(declaration)
5072
- || isPropertyDeclaration(declaration)
5073
- || isPropertySignature(declaration)
5074
- || isVariableDeclaration(declaration)
5075
- || isBindingElement(declaration)) {
5076
- type = getWidenedTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true);
5077
- }
5078
- else {
5079
- return Debug.fail("Unhandled declaration kind! " + Debug.showSyntaxKind(declaration) + " for " + Debug.showSymbol(symbol));
5080
- }
5072
+ let type: Type | undefined;
5073
+ if (isInJavaScriptFile(declaration) &&
5074
+ (isBinaryExpression(declaration) || isPropertyAccessExpression(declaration) && isBinaryExpression(declaration.parent))) {
5075
+ type = getWidenedTypeFromJSPropertyAssignments(symbol);
5076
+ }
5077
+ else if (isJSDocPropertyLikeTag(declaration)
5078
+ || isPropertyAccessExpression(declaration)
5079
+ || isIdentifier(declaration)
5080
+ || isClassDeclaration(declaration)
5081
+ || isFunctionDeclaration(declaration)
5082
+ || (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration))
5083
+ || isMethodSignature(declaration)) {
5084
+ // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty`
5085
+ if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
5086
+ return getTypeOfFuncClassEnumModule(symbol);
5087
+ }
5088
+ type = tryGetTypeFromEffectiveTypeNode(declaration) || anyType;
5089
+ }
5090
+ else if (isPropertyAssignment(declaration)) {
5091
+ type = tryGetTypeFromEffectiveTypeNode(declaration) || checkPropertyAssignment(declaration);
5092
+ }
5093
+ else if (isJsxAttribute(declaration)) {
5094
+ type = tryGetTypeFromEffectiveTypeNode(declaration) || checkJsxAttribute(declaration);
5095
+ }
5096
+ else if (isShorthandPropertyAssignment(declaration)) {
5097
+ type = tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionForMutableLocation(declaration.name, CheckMode.Normal);
5098
+ }
5099
+ else if (isObjectLiteralMethod(declaration)) {
5100
+ type = tryGetTypeFromEffectiveTypeNode(declaration) || checkObjectLiteralMethod(declaration, CheckMode.Normal);
5101
+ }
5102
+ else if (isParameter(declaration)
5103
+ || isPropertyDeclaration(declaration)
5104
+ || isPropertySignature(declaration)
5105
+ || isVariableDeclaration(declaration)
5106
+ || isBindingElement(declaration)) {
5107
+ type = getWidenedTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true);
5108
+ }
5109
+ else {
5110
+ return Debug.fail("Unhandled declaration kind! " + Debug.showSyntaxKind(declaration) + " for " + Debug.showSymbol(symbol));
5081
5111
}
5082
5112
5083
5113
if (!popTypeResolution()) {
5084
5114
type = reportCircularityError(symbol);
5085
5115
}
5086
5116
return type;
5087
- }
5088
-
5089
- function getJSSpecialType(symbol: Symbol, decl: Declaration): Type | undefined {
5090
- if (!isInJavaScriptFile(decl)) {
5091
- return undefined;
5092
- }
5093
- // Handle certain special assignment kinds, which happen to union across multiple declarations:
5094
- // * module.exports = expr
5095
- // * exports.p = expr
5096
- // * this.p = expr
5097
- // * className.prototype.method = expr
5098
- else if (isBinaryExpression(decl) ||
5099
- isPropertyAccessExpression(decl) && isBinaryExpression(decl.parent)) {
5100
- return getJSInitializerType(decl, symbol, getAssignedJavascriptInitializer(isBinaryExpression(decl) ? decl.left : decl)) ||
5101
- getWidenedTypeFromJSSpecialPropertyDeclarations(symbol);
5102
- }
5103
- else if (isParameter(decl)
5104
- || isPropertyDeclaration(decl)
5105
- || isPropertySignature(decl)
5106
- || isVariableDeclaration(decl)
5107
- || isBindingElement(decl)) {
5108
- // Use type from type annotation if one is present
5109
- const isOptional = isParameter(decl) && isJSDocOptionalParameter(decl) ||
5110
- !isBindingElement(decl) && !isVariableDeclaration(decl) && !!decl.questionToken;
5111
- const declaredType = tryGetTypeFromEffectiveTypeNode(decl);
5112
- return declaredType && addOptionality(declaredType, isOptional) ||
5113
- getJSInitializerType(decl, symbol, getDeclaredJavascriptInitializer(decl)) ||
5114
- getWidenedTypeForVariableLikeDeclaration(decl, /*includeOptionality*/ true);
5115
- }
5116
- }
5117
-
5118
- function getJSInitializerType(decl: Node, symbol: Symbol, init: Expression | undefined): Type | undefined {
5119
- if (init && isInJavaScriptFile(init) && isObjectLiteralExpression(init) && init.properties.length === 0) {
5120
- const exports = createSymbolTable();
5121
- while (isBinaryExpression(decl) || isPropertyAccessExpression(decl)) {
5122
- const s = getSymbolOfNode(decl);
5123
- if (s && hasEntries(s.exports)) {
5124
- mergeSymbolTable(exports, s.exports);
5125
- }
5126
- decl = isBinaryExpression(decl) ? decl.parent : decl.parent.parent;
5127
- }
5128
- const s = getSymbolOfNode(decl);
5129
- if (s && hasEntries(s.exports)) {
5130
- mergeSymbolTable(exports, s.exports);
5131
- }
5132
- const type = createAnonymousType(symbol, exports, emptyArray, emptyArray, undefined, undefined);
5133
- type.objectFlags |= ObjectFlags.JSLiteral;
5134
- return type;
5135
- }
5136
5117
}
5137
5118
5138
5119
function getAnnotatedAccessorTypeNode(accessor: AccessorDeclaration | undefined): TypeNode | undefined {
@@ -5264,7 +5245,7 @@ namespace ts {
5264
5245
}
5265
5246
else if (declaration.kind === SyntaxKind.BinaryExpression ||
5266
5247
declaration.kind === SyntaxKind.PropertyAccessExpression && declaration.parent.kind === SyntaxKind.BinaryExpression) {
5267
- return getWidenedTypeFromJSSpecialPropertyDeclarations (symbol);
5248
+ return getWidenedTypeFromJSPropertyAssignments (symbol);
5268
5249
}
5269
5250
else if (symbol.flags & SymbolFlags.ValueModule && declaration && isSourceFile(declaration) && declaration.commonJsModuleIndicator) {
5270
5251
const resolvedModule = resolveExternalModuleSymbol(symbol);
@@ -5273,7 +5254,7 @@ namespace ts {
5273
5254
return errorType;
5274
5255
}
5275
5256
const exportEquals = getMergedSymbol(symbol.exports!.get(InternalSymbolName.ExportEquals)!);
5276
- const type = getWidenedTypeFromJSSpecialPropertyDeclarations (exportEquals, exportEquals === resolvedModule ? undefined : resolvedModule);
5257
+ const type = getWidenedTypeFromJSPropertyAssignments (exportEquals, exportEquals === resolvedModule ? undefined : resolvedModule);
5277
5258
if (!popTypeResolution()) {
5278
5259
return reportCircularityError(symbol);
5279
5260
}
0 commit comments