Add undefined to Symbol.valueDeclaration (#43033)

* About halfway through the checker

I'm going to merge with master to avoid clashing with the declaration
fix.

* Add undefined to Symbol.valueDeclaration

Also add undefined to a number of utility functions that have always
accepted it, but never added it to their type.

* Fix lint from code review

Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>

* remove obsoleted fix from inferFromUsage

Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
This commit is contained in:
Nathan Shively-Sanders 2021-03-02 12:36:26 -08:00 committed by GitHub
parent 3d1c6e8f2f
commit c497b487a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 98 additions and 72 deletions

View file

@ -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;

View file

@ -1640,7 +1640,11 @@ namespace ts {
function useOuterVariableScopeInParameter(result: Symbol, location: Node, lastLocation: Node) {
const target = getEmitScriptTarget(compilerOptions);
const functionLocation = <FunctionLikeDeclaration>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 = <FunctionLikeDeclaration>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((<ShorthandPropertyAssignment>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 = <SourceFile>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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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.
*

View file

@ -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 && (!(<ModuleDeclaration>node).body);
return !!node && node.kind === SyntaxKind.ModuleDeclaration && (!(<ModuleDeclaration>node).body);
}
export function isBlockScopedContainerTopLevel(node: Node): boolean {

View file

@ -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 */

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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 {

View file

@ -1025,7 +1025,7 @@ namespace ts.codefix {
}
function allowsImportingAmbientModule(moduleSymbol: Symbol): boolean {
if (!packageJsons.length) {
if (!packageJsons.length || !moduleSymbol.valueDeclaration) {
return true;
}

View file

@ -950,7 +950,7 @@ namespace ts.codefix {
const props = createMultiMap<Type>();
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);

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;