diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 056da9e347e64..c6a2b14afdf97 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3187,7 +3187,7 @@ namespace ts { undefined; init = init && getRightMostAssignedExpression(init); if (init) { - const isPrototypeAssignment = isPrototypeAccess(isVariableDeclaration(node) ? node.name : isBinaryExpression(node) ? node.left : node); + const isPrototypeAssignment = isPrototypeAccess(isVariableDeclaration(node!) ? node.name : isBinaryExpression(node!) ? node.left : node!); return !!getExpandoInitializer(isBinaryExpression(init) && (init.operatorToken.kind === SyntaxKind.BarBarToken || init.operatorToken.kind === SyntaxKind.QuestionQuestionToken) ? init.right : init, isPrototypeAssignment); } return false; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 592efb9e4f60a..128e6410cb432 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1640,7 +1640,11 @@ namespace ts { function useOuterVariableScopeInParameter(result: Symbol, location: Node, lastLocation: Node) { const target = getEmitScriptTarget(compilerOptions); const functionLocation = location; - if (isParameter(lastLocation) && functionLocation.body && result.valueDeclaration.pos >= functionLocation.body.pos && result.valueDeclaration.end <= functionLocation.body.end) { + if (isParameter(lastLocation) + && functionLocation.body + && result.valueDeclaration + && result.valueDeclaration.pos >= functionLocation.body.pos + && result.valueDeclaration.end <= functionLocation.body.end) { // check for several cases where we introduce temporaries that require moving the name/initializer of the parameter to the body // - static field in a class expression // - optional chaining pre-es2020 @@ -2613,11 +2617,13 @@ namespace ts { const exportAssignment = exportEqualsSymbol!.valueDeclaration; const err = error(node.name, Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, symbolToString(moduleSymbol), compilerOptionName); - addRelatedInfo(err, createDiagnosticForNode( - exportAssignment, - Diagnostics.This_module_is_declared_with_using_export_and_can_only_be_used_with_a_default_import_when_using_the_0_flag, - compilerOptionName - )); + if (exportAssignment) { + addRelatedInfo(err, createDiagnosticForNode( + exportAssignment, + Diagnostics.This_module_is_declared_with_using_export_and_can_only_be_used_with_a_default_import_when_using_the_0_flag, + compilerOptionName + )); + } } else { reportNonDefaultExport(moduleSymbol, node); @@ -2796,7 +2802,7 @@ namespace ts { } function reportNonExportedMember(node: ImportDeclaration | ExportDeclaration | VariableDeclaration, name: Identifier, declarationName: string, moduleSymbol: Symbol, moduleName: string): void { - const localSymbol = moduleSymbol.valueDeclaration.locals?.get(name.escapedText); + const localSymbol = moduleSymbol.valueDeclaration?.locals?.get(name.escapedText); const exports = moduleSymbol.exports; if (localSymbol) { const exportedEqualsSymbol = exports?.get(InternalSymbolName.ExportEquals); @@ -4415,7 +4421,7 @@ namespace ts { } function symbolValueDeclarationIsContextSensitive(symbol: Symbol): boolean { - return symbol && symbol.valueDeclaration && isExpression(symbol.valueDeclaration) && !isContextSensitive(symbol.valueDeclaration); + return symbol && !!symbol.valueDeclaration && isExpression(symbol.valueDeclaration) && !isContextSensitive(symbol.valueDeclaration); } function toNodeBuilderFlags(flags = TypeFormatFlags.None): NodeBuilderFlags { @@ -4764,7 +4770,9 @@ namespace ts { return symbolToTypeNode(symbol, context, isInstanceType); } // Always use 'typeof T' for type of class, enum, and module objects - else if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) && !(symbol.valueDeclaration.kind === SyntaxKind.ClassExpression && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) || + else if (symbol.flags & SymbolFlags.Class + && !getBaseTypeVariableOfClass(symbol) + && !(symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.ClassExpression && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) || symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) || shouldWriteTypeOfFunctionSymbol()) { return symbolToTypeNode(symbol, context, isInstanceType); @@ -6528,7 +6536,7 @@ namespace ts { } const propertyAccessRequire = symbol.declarations?.find(isPropertyAccessExpression); if (propertyAccessRequire && isBinaryExpression(propertyAccessRequire.parent) && isIdentifier(propertyAccessRequire.parent.right) - && type.symbol && isSourceFile(type.symbol.valueDeclaration)) { + && type.symbol?.valueDeclaration && isSourceFile(type.symbol.valueDeclaration)) { const alias = localName === propertyAccessRequire.parent.right.escapedText ? undefined : propertyAccessRequire.parent.right; addResult( factory.createExportDeclaration( @@ -6588,7 +6596,10 @@ namespace ts { serializeEnum(symbol, symbolName, modifierFlags); } if (symbol.flags & SymbolFlags.Class) { - if (symbol.flags & SymbolFlags.Property && isBinaryExpression(symbol.valueDeclaration.parent) && isClassExpression(symbol.valueDeclaration.parent.right)) { + if (symbol.flags & SymbolFlags.Property + && symbol.valueDeclaration + && isBinaryExpression(symbol.valueDeclaration.parent) + && isClassExpression(symbol.valueDeclaration.parent.right)) { // Looks like a `module.exports.Sub = class {}` - if we serialize `symbol` as a class, the result will have no members, // since the classiness is actually from the target of the effective alias the symbol is. yes. A BlockScopedVariable|Class|Property // _really_ acts like an Alias, and none of a BlockScopedVariable, Class, or Property. This is the travesty of JS binding today. @@ -6940,14 +6951,14 @@ namespace ts { // a union/intersection base type, but inherited properties // don't matter here. const valueDecl = s.valueDeclaration; - return valueDecl && !(isNamedDeclaration(valueDecl) && isPrivateIdentifier(valueDecl.name)); + return !!valueDecl && !(isNamedDeclaration(valueDecl) && isPrivateIdentifier(valueDecl.name)); }); const hasPrivateIdentifier = some(symbolProps, s => { // `valueDeclaration` could be undefined if inherited from // a union/intersection base type, but inherited properties // don't matter here. const valueDecl = s.valueDeclaration; - return valueDecl && isNamedDeclaration(valueDecl) && isPrivateIdentifier(valueDecl.name); + return !!valueDecl && isNamedDeclaration(valueDecl) && isPrivateIdentifier(valueDecl.name); }); // Boil down all private properties into a single one. const privateProperties = hasPrivateIdentifier ? @@ -8394,7 +8405,10 @@ namespace ts { } function getFlowTypeOfProperty(reference: Node, prop: Symbol | undefined) { - const initialType = prop && (!isAutoTypedProperty(prop) || getEffectiveModifierFlags(prop.valueDeclaration) & ModifierFlags.Ambient) && getTypeOfPropertyInBaseClass(prop) || undefinedType; + const initialType = prop?.valueDeclaration + && (!isAutoTypedProperty(prop) || getEffectiveModifierFlags(prop.valueDeclaration) & ModifierFlags.Ambient) + && getTypeOfPropertyInBaseClass(prop) + || undefinedType; return getFlowTypeOfReference(reference, autoType, initialType); } @@ -8406,7 +8420,7 @@ namespace ts { if (tag && tag.typeExpression) { return getTypeFromTypeNode(tag.typeExpression); } - const containerObjectType = getJSContainerObjectType(symbol.valueDeclaration, symbol, container); + const containerObjectType = symbol.valueDeclaration && getJSContainerObjectType(symbol.valueDeclaration, symbol, container); return containerObjectType || getWidenedLiteralType(checkExpressionCached(container)); } let type; @@ -8467,7 +8481,7 @@ namespace ts { } } const widened = getWidenedType(addOptionality(type, definedInMethod && !definedInConstructor)); - if (filterType(widened, t => !!(t.flags & ~TypeFlags.Nullable)) === neverType) { + if (symbol.valueDeclaration && filterType(widened, t => !!(t.flags & ~TypeFlags.Nullable)) === neverType) { reportImplicitAny(symbol.valueDeclaration, anyType); return anyType; } @@ -8506,7 +8520,7 @@ namespace ts { errorNextVariableOrPropertyDeclarationMustHaveSameType(/*firstDeclaration*/ undefined, declaredType, declaration, type); } } - if (symbol.parent) { + if (symbol.parent?.valueDeclaration) { const typeNode = getEffectiveTypeAnnotationNode(symbol.parent.valueDeclaration); if (typeNode) { return getTypeOfPropertyOfType(getTypeFromTypeNode(typeNode), symbol.escapedName); @@ -8571,7 +8585,7 @@ namespace ts { // but we may have a JS file with `module.exports = { a: true }` along with a TypeScript module augmentation // declaring an `export const a: number`. In that case, we issue a duplicate identifier error, because // it's unclear what that's supposed to mean, so it's probably a mistake. - if (getSourceFileOfNode(s.valueDeclaration) !== getSourceFileOfNode(exportedMember.valueDeclaration)) { + if (s.valueDeclaration && exportedMember.valueDeclaration && getSourceFileOfNode(s.valueDeclaration) !== getSourceFileOfNode(exportedMember.valueDeclaration)) { const unescapedName = unescapeLeadingUnderscores(s.escapedName); const exportedMemberName = tryCast(exportedMember.valueDeclaration, isNamedDeclaration)?.name || exportedMember.valueDeclaration; addRelatedInfo( @@ -8816,7 +8830,7 @@ namespace ts { if (symbol === requireSymbol) { return anyType; } - if (symbol.flags & SymbolFlags.ModuleExports) { + if (symbol.flags & SymbolFlags.ModuleExports && symbol.valueDeclaration) { const fileSymbol = getSymbolOfNode(getSourceFileOfNode(symbol.valueDeclaration)); const result = createSymbol(fileSymbol.flags, "exports" as __String); result.declarations = fileSymbol.declarations ? fileSymbol.declarations.slice() : []; @@ -8830,6 +8844,7 @@ namespace ts { return createAnonymousType(symbol, members, emptyArray, emptyArray, undefined, undefined); } // Handle catch clause variables + Debug.assertIsDefined(symbol.valueDeclaration); const declaration = symbol.valueDeclaration; if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) { const decl = declaration as VariableDeclaration; @@ -9224,7 +9239,7 @@ namespace ts { if (assignmentKind === AssignmentDeclarationKind.Prototype || assignmentKind === AssignmentDeclarationKind.PrototypeProperty) { const symbol = getSymbolOfNode(node.left); if (symbol && symbol.parent && !findAncestor(symbol.parent.valueDeclaration, d => node === d)) { - node = symbol.parent.valueDeclaration; + node = symbol.parent.valueDeclaration!; } } } @@ -9268,7 +9283,7 @@ namespace ts { case SyntaxKind.JSDocParameterTag: const paramSymbol = getParameterSymbolFromJSDoc(node as JSDocParameterTag); if (paramSymbol) { - node = paramSymbol.valueDeclaration; + node = paramSymbol.valueDeclaration!; } break; case SyntaxKind.JSDocComment: { @@ -9622,7 +9637,7 @@ namespace ts { const originalLinks = links; if (!links.declaredType) { const kind = symbol.flags & SymbolFlags.Class ? ObjectFlags.Class : ObjectFlags.Interface; - const merged = mergeJSSymbols(symbol, getAssignedClassSymbol(symbol.valueDeclaration)); + const merged = mergeJSSymbols(symbol, symbol.valueDeclaration && getAssignedClassSymbol(symbol.valueDeclaration)); if (merged) { // note:we overwrite links because we just cloned the symbol symbol = links = merged; @@ -23460,6 +23475,9 @@ namespace ts { // Check if a parameter is assigned anywhere within its declaring function. function isParameterAssigned(symbol: Symbol) { + if (!symbol.valueDeclaration) { + return false; + } const func = getRootDeclaration(symbol.valueDeclaration).parent; const links = getNodeLinks(func); if (!(links.flags & NodeCheckFlags.AssignmentsMarked)) { @@ -23599,8 +23617,8 @@ namespace ts { addDeprecatedSuggestion(node, sourceSymbol.declarations, node.escapedText as string); } - let declaration: Declaration | undefined = localOrExportSymbol.valueDeclaration; - if (localOrExportSymbol.flags & SymbolFlags.Class) { + let declaration = localOrExportSymbol.valueDeclaration; + if (declaration && localOrExportSymbol.flags & SymbolFlags.Class) { // Due to the emit for class decorators, any reference to the class from inside of the class body // must instead be rewritten to point to a temporary variable to avoid issues with the double-bind // behavior of class names in ES6. @@ -23739,6 +23757,7 @@ namespace ts { function checkNestedBlockScopedBinding(node: Identifier, symbol: Symbol): void { if (languageVersion >= ScriptTarget.ES2015 || (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.Class)) === 0 || + !symbol.valueDeclaration || isSourceFile(symbol.valueDeclaration) || symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause) { return; @@ -26378,7 +26397,7 @@ namespace ts { return true; } if (isInJSFile(symbol.valueDeclaration)) { - const parent = symbol.valueDeclaration.parent; + const parent = symbol.valueDeclaration!.parent; return parent && isBinaryExpression(parent) && getAssignmentDeclarationKind(parent) === AssignmentDeclarationKind.PrototypeProperty; } @@ -26618,14 +26637,13 @@ namespace ts { } const diagName = diagnosticName(right); if (propertyOnType) { - const typeValueDecl = propertyOnType.valueDeclaration; - const typeClass = getContainingClass(typeValueDecl); - Debug.assert(!!typeClass); + const typeValueDecl = Debug.checkDefined(propertyOnType.valueDeclaration); + const typeClass = Debug.checkDefined(getContainingClass(typeValueDecl)); // We found a private identifier property with the same description. // Either: // - There is a lexically scoped private identifier AND it shadows the one we found on the type. // - It is an attempt to access the private identifier outside of the class. - if (lexicallyScopedIdentifier) { + if (lexicallyScopedIdentifier?.valueDeclaration) { const lexicalValueDecl = lexicallyScopedIdentifier.valueDeclaration; const lexicalClass = getContainingClass(lexicalValueDecl); Debug.assert(!!lexicalClass); @@ -26934,7 +26952,7 @@ namespace ts { function typeHasStaticProperty(propName: __String, containingType: Type): boolean { const prop = containingType.symbol && getPropertyOfType(getTypeOfSymbol(containingType.symbol), propName); - return prop !== undefined && prop.valueDeclaration && hasSyntacticModifier(prop.valueDeclaration, ModifierFlags.Static); + return prop !== undefined && !!prop.valueDeclaration && hasSyntacticModifier(prop.valueDeclaration, ModifierFlags.Static); } function getSuggestedLibForNonExistentName(name: __String | Identifier) { @@ -27082,7 +27100,7 @@ namespace ts { return; } const hasPrivateModifier = hasEffectiveModifier(valueDeclaration, ModifierFlags.Private); - const hasPrivateIdentifier = isNamedDeclaration(prop.valueDeclaration) && isPrivateIdentifier(prop.valueDeclaration.name); + const hasPrivateIdentifier = prop.valueDeclaration && isNamedDeclaration(prop.valueDeclaration) && isPrivateIdentifier(prop.valueDeclaration.name); if (!hasPrivateModifier && !hasPrivateIdentifier) { return; } @@ -34739,7 +34757,7 @@ namespace ts { if (node.initializer) { checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(node.initializer), declarationType, node, node.initializer, /*headMessage*/ undefined); } - if (!areDeclarationFlagsIdentical(node, symbol.valueDeclaration)) { + if (symbol.valueDeclaration && !areDeclarationFlagsIdentical(node, symbol.valueDeclaration)) { error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, declarationNameToString(node.name)); } } @@ -36040,7 +36058,7 @@ namespace ts { if (blockLocals) { forEachKey(catchClause.locals!, caughtName => { const blockLocal = blockLocals.get(caughtName); - if (blockLocal && (blockLocal.flags & SymbolFlags.BlockScopedVariable) !== 0) { + if (blockLocal?.valueDeclaration && (blockLocal.flags & SymbolFlags.BlockScopedVariable) !== 0) { grammarErrorOnNode(blockLocal.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, caughtName); } }); @@ -36071,7 +36089,7 @@ namespace ts { }); const classDeclaration = type.symbol.valueDeclaration; - if (getObjectFlags(type) & ObjectFlags.Class && isClassLike(classDeclaration)) { + if (getObjectFlags(type) & ObjectFlags.Class && classDeclaration && isClassLike(classDeclaration)) { for (const member of classDeclaration.members) { // Only process instance properties with computed names here. // Static properties cannot be in conflict with indexers, @@ -36941,7 +36959,7 @@ namespace ts { if (memberSymbol) { const declaration = memberSymbol.valueDeclaration; if (declaration !== member) { - if (isBlockScopedNameDeclaredBeforeUse(declaration, member)) { + if (declaration && isBlockScopedNameDeclaredBeforeUse(declaration, member)) { return getEnumMemberValue(declaration as EnumMember); } error(expr, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums); @@ -37600,7 +37618,7 @@ namespace ts { const exportEqualsSymbol = moduleSymbol.exports!.get("export=" as __String); if (exportEqualsSymbol && hasExportedMembers(moduleSymbol)) { const declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) || exportEqualsSymbol.valueDeclaration; - if (!isTopLevelInExternalModuleAugmentation(declaration) && !isInJSFile(declaration)) { + if (declaration && !isTopLevelInExternalModuleAugmentation(declaration) && !isInJSFile(declaration)) { error(declaration, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements); } } @@ -38574,7 +38592,7 @@ namespace ts { } } - function getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined { + function getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined { if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) { return resolveEntityName((location).name, SymbolFlags.Value | SymbolFlags.Alias); } @@ -38862,7 +38880,7 @@ namespace ts { } const parentSymbol = getParentOfSymbol(symbol); if (parentSymbol) { - if (parentSymbol.flags & SymbolFlags.ValueModule && parentSymbol.valueDeclaration.kind === SyntaxKind.SourceFile) { + if (parentSymbol.flags & SymbolFlags.ValueModule && parentSymbol.valueDeclaration?.kind === SyntaxKind.SourceFile) { const symbolFile = parentSymbol.valueDeclaration; const referenceFile = getSourceFileOfNode(node); // If `node` accesses an export and that export isn't in the same file, then symbol is a namespace export, so return undefined. @@ -38895,12 +38913,13 @@ namespace ts { } function isSymbolOfDestructuredElementOfCatchBinding(symbol: Symbol) { - return isBindingElement(symbol.valueDeclaration) + return symbol.valueDeclaration + && isBindingElement(symbol.valueDeclaration) && walkUpBindingElementsAndPatterns(symbol.valueDeclaration).parent.kind === SyntaxKind.CatchClause; } function isSymbolOfDeclarationWithCollidingName(symbol: Symbol): boolean { - if (symbol.flags & SymbolFlags.BlockScoped && !isSourceFile(symbol.valueDeclaration)) { + if (symbol.flags & SymbolFlags.BlockScoped && symbol.valueDeclaration && !isSourceFile(symbol.valueDeclaration)) { const links = getSymbolLinks(symbol); if (links.isDeclarationWithCollidingName === undefined) { const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 5f3a19a8949ac..0a2918aedf587 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -5507,7 +5507,7 @@ namespace ts { : reduceLeft(expressions, factory.createComma)!; } - function getName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags: EmitFlags = 0) { + function getName(node: Declaration | undefined, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags: EmitFlags = 0) { const nodeName = getNameOfDeclaration(node); if (nodeName && isIdentifier(nodeName) && !isGeneratedIdentifier(nodeName)) { // TODO(rbuckton): Does this need to be parented? @@ -5571,7 +5571,7 @@ namespace ts { * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - function getDeclarationName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean) { + function getDeclarationName(node: Declaration | undefined, allowComments?: boolean, allowSourceMaps?: boolean) { return getName(node, allowComments, allowSourceMaps); } diff --git a/src/compiler/moduleSpecifiers.ts b/src/compiler/moduleSpecifiers.ts index 6d4eb03719ca1..3fcda6d428db8 100644 --- a/src/compiler/moduleSpecifiers.ts +++ b/src/compiler/moduleSpecifiers.ts @@ -103,6 +103,9 @@ namespace ts.moduleSpecifiers { const info = getInfo(importingSourceFile.path, host); const moduleSourceFile = getSourceFileOfNode(moduleSymbol.valueDeclaration || getNonAugmentationDeclaration(moduleSymbol)); + if (!moduleSourceFile) { + return []; + } const modulePaths = getAllModulePaths(importingSourceFile.path, moduleSourceFile.originalFileName, host); const preferences = getPreferences(userPreferences, compilerOptions, importingSourceFile); diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index e20d1ac0bfca2..849dfcc5ee1f2 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -1202,7 +1202,7 @@ namespace ts { fakespace.symbol = props[0].parent!; const exportMappings: [Identifier, string][] = []; let declarations: (VariableStatement | ExportDeclaration)[] = mapDefined(props, p => { - if (!isPropertyAccessExpression(p.valueDeclaration)) { + if (!p.valueDeclaration || !isPropertyAccessExpression(p.valueDeclaration)) { return undefined; // TODO GH#33569: Handle element access expressions that created late bound names (rather than silently omitting them) } getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8cfddadc7acaa..d15256efee1b6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4046,7 +4046,7 @@ namespace ts { * The function returns the value (local variable) symbol of an identifier in the short-hand property assignment. * This is necessary as an identifier in short-hand property assignment can contains two meaning: property name and property value. */ - getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined; + getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined; getExportSpecifierLocalTargetSymbol(location: ExportSpecifier | Identifier): Symbol | undefined; /** @@ -4715,7 +4715,7 @@ namespace ts { flags: SymbolFlags; // Symbol flags escapedName: __String; // Name of symbol declarations?: Declaration[]; // Declarations associated with this symbol - valueDeclaration: Declaration; // First value declaration of the symbol + valueDeclaration?: Declaration; // First value declaration of the symbol members?: SymbolTable; // Class, interface or object literal instance members exports?: SymbolTable; // Module exports globalExports?: SymbolTable; // Conditional global UMD exports @@ -7394,7 +7394,7 @@ namespace ts { * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - /* @internal */ getDeclarationName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier; + /* @internal */ getDeclarationName(node: Declaration | undefined, allowComments?: boolean, allowSourceMaps?: boolean): Identifier; /** * Gets a namespace-qualified name for use in expressions. * diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f3c08902f55ff..13289cc4595d8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -734,9 +734,9 @@ namespace ts { return isShorthandAmbientModule(moduleSymbol.valueDeclaration); } - function isShorthandAmbientModule(node: Node): boolean { + function isShorthandAmbientModule(node: Node | undefined): boolean { // The only kind of module that can be missing a body is a shorthand ambient module. - return node && node.kind === SyntaxKind.ModuleDeclaration && (!(node).body); + return !!node && node.kind === SyntaxKind.ModuleDeclaration && (!(node).body); } export function isBlockScopedContainerTopLevel(node: Node): boolean { diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index e6a27fb6492d4..2b9e259b8334f 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -614,7 +614,7 @@ namespace ts { return (declaration as NamedDeclaration).name; } - export function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined { + export function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined { if (declaration === undefined) return undefined; return getNonAssignedNameOfDeclaration(declaration) || (isFunctionExpression(declaration) || isClassExpression(declaration) ? getAssignedName(declaration) : undefined); @@ -1208,8 +1208,8 @@ namespace ts { // Functions - export function isFunctionLike(node: Node): node is SignatureDeclaration { - return node && isFunctionLikeKind(node.kind); + export function isFunctionLike(node: Node | undefined): node is SignatureDeclaration { + return !!node && isFunctionLikeKind(node.kind); } /* @internal */ diff --git a/src/services/codefixes/convertConstToLet.ts b/src/services/codefixes/convertConstToLet.ts index 610aaf5daa4e2..ba54cea297a70 100644 --- a/src/services/codefixes/convertConstToLet.ts +++ b/src/services/codefixes/convertConstToLet.ts @@ -18,7 +18,7 @@ namespace ts.codefix { const token = getTokenAtPosition(sourceFile, pos); const checker = program.getTypeChecker(); const symbol = checker.getSymbolAtLocation(token); - if (symbol) { + if (symbol?.valueDeclaration) { return symbol.valueDeclaration.parent.parent as VariableStatement; } } diff --git a/src/services/codefixes/convertFunctionToEs6Class.ts b/src/services/codefixes/convertFunctionToEs6Class.ts index 500e4346cad6a..70de7a1978d14 100644 --- a/src/services/codefixes/convertFunctionToEs6Class.ts +++ b/src/services/codefixes/convertFunctionToEs6Class.ts @@ -16,7 +16,7 @@ namespace ts.codefix { function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker, preferences: UserPreferences, compilerOptions: CompilerOptions): void { const ctorSymbol = checker.getSymbolAtLocation(getTokenAtPosition(sourceFile, position))!; - if (!ctorSymbol || !(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) { + if (!ctorSymbol || !ctorSymbol.valueDeclaration || !(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) { // Bad input return undefined; } @@ -46,7 +46,7 @@ namespace ts.codefix { // all instance members are stored in the "member" array of symbol if (symbol.members) { symbol.members.forEach((member, key) => { - if (key === "constructor") { + if (key === "constructor" && member.valueDeclaration) { // fn.prototype.constructor = fn changes.delete(sourceFile, member.valueDeclaration.parent); return; diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts index 3fc61d8b45d3b..22c1ddc675889 100644 --- a/src/services/codefixes/convertToAsyncFunction.ts +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -168,7 +168,10 @@ namespace ts.codefix { // so we push an entry for 'response'. if (lastCallSignature && !isParameter(node.parent) && !isFunctionLikeDeclaration(node.parent) && !synthNamesMap.has(symbolIdString)) { const firstParameter = firstOrUndefined(lastCallSignature.parameters); - const ident = firstParameter && isParameter(firstParameter.valueDeclaration) && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic); + const ident = firstParameter?.valueDeclaration + && isParameter(firstParameter.valueDeclaration) + && tryCast(firstParameter.valueDeclaration.name, isIdentifier) + || factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic); const synthName = getNewNameIfConflict(ident, collidingSymbolMap); synthNamesMap.set(symbolIdString, synthName); collidingSymbolMap.add(ident.text, symbol); diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index ed748ad29c825..6d80e1f900899 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -87,7 +87,7 @@ namespace ts.codefix { const suggestion = symbolName(suggestedSymbol); if (!isIdentifierText(suggestion, target) && isPropertyAccessExpression(node.parent)) { const valDecl = suggestedSymbol.valueDeclaration; - if (isNamedDeclaration(valDecl) && isPrivateIdentifier(valDecl.name)) { + if (valDecl && isNamedDeclaration(valDecl) && isPrivateIdentifier(valDecl.name)) { changes.replaceNode(sourceFile, node, factory.createIdentifier(suggestion)); } else { diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 6a23151ae4d59..c1e28557bfbcf 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -1025,7 +1025,7 @@ namespace ts.codefix { } function allowsImportingAmbientModule(moduleSymbol: Symbol): boolean { - if (!packageJsons.length) { + if (!packageJsons.length || !moduleSymbol.valueDeclaration) { return true; } diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 0ad7980789739..602a71fc1bf3c 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -950,7 +950,7 @@ namespace ts.codefix { const props = createMultiMap(); for (const anon of anons) { for (const p of checker.getPropertiesOfType(anon)) { - props.add(p.name, checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration)); + props.add(p.name, p.valueDeclaration ? checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration) : checker.getAnyType()); } calls.push(...checker.getSignaturesOfType(anon, SignatureKind.Call)); constructs.push(...checker.getSignaturesOfType(anon, SignatureKind.Construct)); @@ -1104,12 +1104,13 @@ namespace ts.codefix { if (!usageParam) { break; } - let genericParamType = checker.getTypeOfSymbolAtLocation(genericParam, genericParam.valueDeclaration); + let genericParamType = genericParam.valueDeclaration ? checker.getTypeOfSymbolAtLocation(genericParam, genericParam.valueDeclaration) : checker.getAnyType(); const elementType = isRest && checker.getElementTypeOfArrayType(genericParamType); if (elementType) { genericParamType = elementType; } - const targetType = (usageParam as SymbolLinks).type || checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration); + const targetType = (usageParam as SymbolLinks).type + || (usageParam.valueDeclaration ? checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration) : checker.getAnyType()); types.push(...inferTypeParameters(genericParamType, targetType, typeParameter)); } const genericReturn = checker.getReturnTypeOfSignature(genericSig); diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index d86e497330b28..34158f5f71f6a 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -360,7 +360,7 @@ namespace ts.FindAllReferences { const checker = program.getTypeChecker(); for (const referencingFile of sourceFiles) { const searchSourceFile = searchModuleSymbol.valueDeclaration; - if (searchSourceFile.kind === SyntaxKind.SourceFile) { + if (searchSourceFile?.kind === SyntaxKind.SourceFile) { for (const ref of referencingFile.referencedFiles) { if (program.getSourceFileFromReference(referencingFile, ref) === searchSourceFile) { refs.push({ kind: "reference", referencingFile, ref }); @@ -582,7 +582,7 @@ namespace ts.FindAllReferences { return Debug.checkDefined(checker.getImmediateAliasedSymbol(importedSymbol)); } - const decl = importedSymbol.valueDeclaration; + const decl = Debug.checkDefined(importedSymbol.valueDeclaration); if (isExportAssignment(decl)) { // `export = class {}` return Debug.checkDefined(decl.expression.symbol); } diff --git a/src/services/refactors/extractType.ts b/src/services/refactors/extractType.ts index e9cecdf6c9378..549ff99f4d7ac 100644 --- a/src/services/refactors/extractType.ts +++ b/src/services/refactors/extractType.ts @@ -168,7 +168,7 @@ namespace ts.refactor { else if (isTypeQueryNode(node)) { if (isIdentifier(node.exprName)) { const symbol = checker.resolveName(node.exprName.text, node.exprName, SymbolFlags.Value, /* excludeGlobals */ false); - if (symbol && rangeContainsSkipTrivia(statement, symbol.valueDeclaration, file) && !rangeContainsSkipTrivia(selection, symbol.valueDeclaration, file)) { + if (symbol?.valueDeclaration && rangeContainsSkipTrivia(statement, symbol.valueDeclaration, file) && !rangeContainsSkipTrivia(selection, symbol.valueDeclaration, file)) { return true; } } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 71c0361b07752..4ecd8455cd74f 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2187,7 +2187,7 @@ declare namespace ts { * The function returns the value (local variable) symbol of an identifier in the short-hand property assignment. * This is necessary as an identifier in short-hand property assignment can contains two meaning: property name and property value. */ - getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined; + getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined; getExportSpecifierLocalTargetSymbol(location: ExportSpecifier | Identifier): Symbol | undefined; /** * If a symbol is a local symbol with an associated exported symbol, returns the exported symbol. @@ -2409,7 +2409,7 @@ declare namespace ts { flags: SymbolFlags; escapedName: __String; declarations?: Declaration[]; - valueDeclaration: Declaration; + valueDeclaration?: Declaration; members?: SymbolTable; exports?: SymbolTable; globalExports?: SymbolTable; @@ -4107,7 +4107,7 @@ declare namespace ts { function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string; function symbolName(symbol: Symbol): string; function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateIdentifier | undefined; - function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined; + function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined; /** * Gets the JSDoc parameter tags for the node if present. * @@ -4233,7 +4233,7 @@ declare namespace ts { function isEntityName(node: Node): node is EntityName; function isPropertyName(node: Node): node is PropertyName; function isBindingName(node: Node): node is BindingName; - function isFunctionLike(node: Node): node is SignatureDeclaration; + function isFunctionLike(node: Node | undefined): node is SignatureDeclaration; function isClassElement(node: Node): node is ClassElement; function isClassLike(node: Node): node is ClassLikeDeclaration; function isAccessor(node: Node): node is AccessorDeclaration; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 6847f968ab894..471a5eae4c3a0 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2187,7 +2187,7 @@ declare namespace ts { * The function returns the value (local variable) symbol of an identifier in the short-hand property assignment. * This is necessary as an identifier in short-hand property assignment can contains two meaning: property name and property value. */ - getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined; + getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined; getExportSpecifierLocalTargetSymbol(location: ExportSpecifier | Identifier): Symbol | undefined; /** * If a symbol is a local symbol with an associated exported symbol, returns the exported symbol. @@ -2409,7 +2409,7 @@ declare namespace ts { flags: SymbolFlags; escapedName: __String; declarations?: Declaration[]; - valueDeclaration: Declaration; + valueDeclaration?: Declaration; members?: SymbolTable; exports?: SymbolTable; globalExports?: SymbolTable; @@ -4107,7 +4107,7 @@ declare namespace ts { function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string; function symbolName(symbol: Symbol): string; function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateIdentifier | undefined; - function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined; + function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined; /** * Gets the JSDoc parameter tags for the node if present. * @@ -4233,7 +4233,7 @@ declare namespace ts { function isEntityName(node: Node): node is EntityName; function isPropertyName(node: Node): node is PropertyName; function isBindingName(node: Node): node is BindingName; - function isFunctionLike(node: Node): node is SignatureDeclaration; + function isFunctionLike(node: Node | undefined): node is SignatureDeclaration; function isClassElement(node: Node): node is ClassElement; function isClassLike(node: Node): node is ClassLikeDeclaration; function isAccessor(node: Node): node is AccessorDeclaration;