Add undefined to parameter's name type

Only parameters to JSDocFunctionTypes may not have names, but these
parameters cause crashes from time to time, most recently #47606.

This PR is NOT in a mergeable state -- having fixed all the compile
errors, I don't actually think it's worthwhile. A lot of the difficulty
comes from deciding whether to handle an undefined name instead of just
asserting that it's defined. Any piece of code that only handles
function *values* doesn't need to handle undefined parameters. However,
it's difficult to know when this is the case.
This commit is contained in:
Nathan Shively-Sanders
2022-02-01 15:38:48 -08:00
parent 1ebdcc6fb8
commit 514bff0c7d
23 changed files with 69 additions and 55 deletions
+19 -19
View File
@@ -1739,7 +1739,7 @@ namespace ts {
return false;
function requiresScopeChange(node: ParameterDeclaration): boolean {
return requiresScopeChangeWorker(node.name)
return !!node.name && requiresScopeChangeWorker(node.name)
|| !!node.initializer && requiresScopeChangeWorker(node.initializer);
}
@@ -21293,7 +21293,7 @@ namespace ts {
break;
case SyntaxKind.Parameter:
const param = declaration as ParameterDeclaration;
if (isIdentifier(param.name) &&
if (param.name && isIdentifier(param.name) &&
(isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) || isFunctionTypeNode(param.parent)) &&
param.parent.parameters.indexOf(param) > -1 &&
(resolveName(param, param.name.escapedText, SymbolFlags.Type, undefined, param.name.escapedText, /*isUse*/ true) ||
@@ -25990,7 +25990,7 @@ namespace ts {
const parentType = getContextualTypeForVariableLikeDeclaration(parent) ||
parent.kind !== SyntaxKind.BindingElement && parent.initializer && checkDeclarationInitializer(parent);
if (!parentType || isBindingPattern(name) || isComputedNonLiteralName(name)) return undefined;
if (parent.name.kind === SyntaxKind.ArrayBindingPattern) {
if (parent.name?.kind === SyntaxKind.ArrayBindingPattern) {
const index = indexOfNode(declaration.parent.elements, declaration);
if (index < 0) return undefined;
return getContextualTypeForElementExpression(parentType, index);
@@ -31488,7 +31488,7 @@ namespace ts {
}
function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember) {
Debug.assert(isIdentifier(d.name)); // Parameter declarations could be binding patterns, but we only allow identifier names
Debug.assert(d.name && isIdentifier(d.name)); // Parameter declarations could be binding patterns, but we only allow identifier names
return d.name.escapedText;
}
@@ -31541,10 +31541,10 @@ namespace ts {
}
function isParameterDeclarationWithIdentifierName(symbol: Symbol) {
return symbol.valueDeclaration && isParameter(symbol.valueDeclaration) && isIdentifier(symbol.valueDeclaration.name);
return symbol.valueDeclaration && isParameter(symbol.valueDeclaration) && symbol.valueDeclaration.name && isIdentifier(symbol.valueDeclaration.name);
}
function isValidDeclarationForTupleLabel(d: Declaration): d is NamedTupleMember | (ParameterDeclaration & { name: Identifier }) {
return d.kind === SyntaxKind.NamedTupleMember || (isParameter(d) && d.name && isIdentifier(d.name));
return d.kind === SyntaxKind.NamedTupleMember || (isParameter(d) && !!d.name && isIdentifier(d.name));
}
function getNameableDeclarationAtPosition(signature: Signature, pos: number) {
@@ -31771,7 +31771,7 @@ namespace ts {
if (!links.type) {
const declaration = parameter.valueDeclaration as ParameterDeclaration;
links.type = type || getWidenedTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true);
if (declaration.name.kind !== SyntaxKind.Identifier) {
if (declaration.name && declaration.name.kind !== SyntaxKind.Identifier) {
// if inference didn't come up with anything but unknown, fall back to the binding pattern if present.
if (links.type === unknownType) {
links.type = getTypeFromBindingPattern(declaration.name);
@@ -33717,7 +33717,7 @@ namespace ts {
const initializer = getEffectiveInitializer(declaration)!;
const type = getQuickTypeOfExpression(initializer) ||
(contextualType ? checkExpressionWithContextualType(initializer, contextualType, /*inferenceContext*/ undefined, CheckMode.Normal) : checkExpressionCached(initializer));
return isParameter(declaration) && declaration.name.kind === SyntaxKind.ArrayBindingPattern &&
return isParameter(declaration) && declaration.name?.kind === SyntaxKind.ArrayBindingPattern &&
isTupleType(type) && !type.target.hasRestElement && getTypeReferenceArity(type) < declaration.name.elements.length ?
padTupleType(type, declaration.name) : type;
}
@@ -34254,7 +34254,7 @@ namespace ts {
if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) {
error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation);
}
if (func.kind === SyntaxKind.Constructor && isIdentifier(node.name) && node.name.escapedText === "constructor") {
if (func.kind === SyntaxKind.Constructor && node.name && isIdentifier(node.name) && node.name.escapedText === "constructor") {
error(node.name, Diagnostics.constructor_cannot_be_used_as_a_parameter_property_name);
}
}
@@ -36436,7 +36436,7 @@ namespace ts {
case SyntaxKind.Constructor:
for (const parameter of (member as ConstructorDeclaration).parameters) {
if (!parameter.symbol.isReferenced && hasSyntacticModifier(parameter, ModifierFlags.Private)) {
addDiagnostic(parameter, UnusedKind.Local, createDiagnosticForNode(parameter.name, Diagnostics.Property_0_is_declared_but_its_value_is_never_read, symbolName(parameter.symbol)));
addDiagnostic(parameter, UnusedKind.Local, createDiagnosticForNode(parameter.name!, Diagnostics.Property_0_is_declared_but_its_value_is_never_read, symbolName(parameter.symbol)));
}
}
break;
@@ -42937,17 +42937,17 @@ namespace ts {
}
if (parameter.initializer) {
return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_have_an_initializer);
return grammarErrorOnNode(parameter.name || parameter, Diagnostics.A_rest_parameter_cannot_have_an_initializer);
}
}
else if (isOptionalParameter(parameter)) {
seenOptionalParameter = true;
if (parameter.questionToken && parameter.initializer) {
return grammarErrorOnNode(parameter.name, Diagnostics.Parameter_cannot_have_question_mark_and_initializer);
return grammarErrorOnNode(parameter.name || parameter, Diagnostics.Parameter_cannot_have_question_mark_and_initializer);
}
}
else if (seenOptionalParameter && !parameter.initializer) {
return grammarErrorOnNode(parameter.name, Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter);
return grammarErrorOnNode(parameter.name || parameter, Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter);
}
}
}
@@ -43017,7 +43017,7 @@ namespace ts {
const parameter = node.parameters[0];
if (node.parameters.length !== 1) {
if (parameter) {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_must_have_exactly_one_parameter);
return grammarErrorOnNode(parameter.name || parameter, Diagnostics.An_index_signature_must_have_exactly_one_parameter);
}
else {
return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_exactly_one_parameter);
@@ -43028,23 +43028,23 @@ namespace ts {
return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.An_index_signature_cannot_have_a_rest_parameter);
}
if (hasEffectiveModifiers(parameter)) {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier);
return grammarErrorOnNode(parameter.name || parameter, Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier);
}
if (parameter.questionToken) {
return grammarErrorOnNode(parameter.questionToken, Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark);
}
if (parameter.initializer) {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_initializer);
return grammarErrorOnNode(parameter.name || parameter, Diagnostics.An_index_signature_parameter_cannot_have_an_initializer);
}
if (!parameter.type) {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_must_have_a_type_annotation);
return grammarErrorOnNode(parameter.name || parameter, Diagnostics.An_index_signature_parameter_must_have_a_type_annotation);
}
const type = getTypeFromTypeNode(parameter.type);
if (someType(type, t => !!(t.flags & TypeFlags.StringOrNumberLiteralOrUnique)) || isGenericType(type)) {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead);
return grammarErrorOnNode(parameter.name || parameter, Diagnostics.An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead);
}
if (!everyType(type, isValidIndexKeyType)) {
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_must_be_string_number_symbol_or_a_template_literal_type);
return grammarErrorOnNode(parameter.name || parameter, Diagnostics.An_index_signature_parameter_type_must_be_string_number_symbol_or_a_template_literal_type);
}
if (!node.type) {
return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_a_type_annotation);
+1 -1
View File
@@ -4264,7 +4264,7 @@ namespace ts {
&& !parameter.questionToken // parameter may not be optional
&& !parameter.type // parameter may not have a type annotation
&& !parameter.initializer // parameter may not have an initializer
&& isIdentifier(parameter.name); // parameter name must be identifier
&& isIdentifier(parameter.name!); // parameter name must be identifier
}
function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
+2 -2
View File
@@ -1151,7 +1151,7 @@ namespace ts {
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
dotDotDotToken: DotDotDotToken | undefined,
name: string | BindingName,
name: string | BindingName | undefined,
questionToken?: QuestionToken,
type?: TypeNode,
initializer?: Expression
@@ -1186,7 +1186,7 @@ namespace ts {
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
dotDotDotToken: DotDotDotToken | undefined,
name: string | BindingName,
name: string | BindingName | undefined,
questionToken: QuestionToken | undefined,
type: TypeNode | undefined,
initializer: Expression | undefined
+1 -1
View File
@@ -3031,7 +3031,7 @@ namespace ts {
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
// TODO(rbuckton): JSDoc parameters don't have names (except `this`/`new`), should we manufacture an empty identifier?
name!,
name,
/*questionToken*/ undefined,
parseJSDocType(),
/*initializer*/ undefined
+4 -3
View File
@@ -447,8 +447,8 @@ namespace ts {
return ret;
}
function filterBindingPatternInitializers(name: BindingName) {
if (name.kind === SyntaxKind.Identifier) {
function filterBindingPatternInitializers(name: BindingName | undefined) {
if (!name || name.kind === SyntaxKind.Identifier) {
return name;
}
else {
@@ -465,7 +465,7 @@ namespace ts {
if (elem.kind === SyntaxKind.OmittedExpression) {
return elem;
}
return factory.updateBindingElement(elem, elem.dotDotDotToken, elem.propertyName, filterBindingPatternInitializers(elem.name), shouldPrintWithInitializer(elem) ? elem.initializer : undefined);
return factory.updateBindingElement(elem, elem.dotDotDotToken, elem.propertyName, filterBindingPatternInitializers(elem.name)!, shouldPrintWithInitializer(elem) ? elem.initializer : undefined);
}
}
@@ -1371,6 +1371,7 @@ namespace ts {
const oldDiag = getSymbolAccessibilityDiagnostic;
parameterProperties = compact(flatMap(ctor.parameters, (param) => {
if (!hasSyntacticModifier(param, ModifierFlags.ParameterPropertyModifier) || shouldStripInternal(param)) return;
Debug.type<BindingName>(param.name);
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(param);
if (param.name.kind === SyntaxKind.Identifier) {
return preserveJsDoc(factory.createPropertyDeclaration(
+2
View File
@@ -1310,6 +1310,7 @@ namespace ts {
added = insertDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer) || added;
}
else if (initializer) {
Debug.type<BindingName>(name);
insertDefaultValueAssignmentForInitializer(statements, parameter, name, initializer);
added = true;
}
@@ -1439,6 +1440,7 @@ namespace ts {
// `declarationName` is the name of the local declaration for the parameter.
// TODO(rbuckton): Does this need to be parented?
Debug.type<BindingName>(parameter.name);
const declarationName = parameter.name.kind === SyntaxKind.Identifier ? setParent(setTextRange(factory.cloneNode(parameter.name), parameter.name), parameter.name.parent) : factory.createTempVariable(/*recordTempVariable*/ undefined);
setEmitFlags(declarationName, EmitFlags.NoSourceMap);
+1
View File
@@ -373,6 +373,7 @@ namespace ts {
}
function recordDeclarationName({ name }: ParameterDeclaration | VariableDeclaration | BindingElement, names: Set<__String>) {
Debug.type<BindingName>(name);
if (isIdentifier(name)) {
names.add(name.escapedText);
}
+8 -6
View File
@@ -891,6 +891,7 @@ namespace ts {
if (parametersWithPropertyAssignments) {
for (const parameter of parametersWithPropertyAssignments) {
Debug.type<BindingName>(parameter.name);
if (isIdentifier(parameter.name)) {
members.push(setOriginalNode(factory.createPropertyDeclaration(
/*decorators*/ undefined,
@@ -1414,11 +1415,9 @@ namespace ts {
*/
function serializeParameterTypesOfNode(node: Node, container: ClassLikeDeclaration): ArrayLiteralExpression {
const valueDeclaration =
isClassLike(node)
? getFirstConstructorWithBody(node)
: isFunctionLike(node) && nodeIsPresent((node as FunctionLikeDeclaration).body)
? node
: undefined;
isClassLike(node) ? getFirstConstructorWithBody(node)
: isFunctionLike(node) && nodeIsPresent((node as FunctionLikeDeclaration).body) ? node
: undefined;
const expressions: SerializedTypeNode[] = [];
if (valueDeclaration) {
@@ -1426,6 +1425,7 @@ namespace ts {
const numParameters = parameters.length;
for (let i = 0; i < numParameters; i++) {
const parameter = parameters[i];
Debug.type<BindingName>(parameter.name);
if (i === 0 && isIdentifier(parameter.name) && parameter.name.escapedText === "this") {
continue;
}
@@ -2176,7 +2176,9 @@ namespace ts {
setCommentRange(updated, node);
setTextRange(updated, moveRangePastModifiers(node));
setSourceMapRange(updated, moveRangePastModifiers(node));
setEmitFlags(updated.name, EmitFlags.NoTrailingSourceMap);
if (updated.name) {
setEmitFlags(updated.name, EmitFlags.NoTrailingSourceMap);
}
}
return updated;
}
+3 -3
View File
@@ -1304,7 +1304,7 @@ namespace ts {
readonly kind: SyntaxKind.Parameter;
readonly parent: SignatureDeclaration;
readonly dotDotDotToken?: DotDotDotToken; // Present on rest parameter
readonly name: BindingName; // Declared parameter name.
readonly name?: BindingName; // Declared parameter name.
readonly questionToken?: QuestionToken; // Present on optional parameter
readonly type?: TypeNode; // Optional type annotation
readonly initializer?: Expression; // Optional initializer
@@ -7188,8 +7188,8 @@ namespace ts {
createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration;
updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration;
createParameterDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration;
updateParameterDeclaration(node: ParameterDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration;
createParameterDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName | undefined, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration;
updateParameterDeclaration(node: ParameterDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName | undefined, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration;
createDecorator(expression: Expression): Decorator;
updateDecorator(node: Decorator, expression: Expression): Decorator;
+2 -2
View File
@@ -2206,7 +2206,7 @@ namespace ts {
/** Get the declaration initializer when it is container-like (See getExpandoInitializer). */
export function getDeclaredExpandoInitializer(node: HasExpressionInitializer) {
const init = getEffectiveInitializer(node);
return init && getExpandoInitializer(init, isPrototypeAccess(node.name));
return init && node.name && getExpandoInitializer(init, isPrototypeAccess(node.name));
}
function hasExpandoValueProperty(node: ObjectLiteralExpression, isPrototypeAssignment: boolean) {
@@ -2780,7 +2780,7 @@ namespace ts {
if (!decl) {
return undefined;
}
const parameter = find(decl.parameters, p => p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name);
const parameter = find(decl.parameters, p => !!p.name && p.name.kind === SyntaxKind.Identifier && p.name.escapedText === name);
return parameter && parameter.symbol;
}
+3 -1
View File
@@ -201,12 +201,13 @@ namespace ts {
// so let's just ignore it.
return parameter.dotDotDotToken ? parameter :
isBindingPattern(parameter.name) ? addDefaultValueAssignmentForBindingPattern(parameter, context) :
parameter.initializer ? addDefaultValueAssignmentForInitializer(parameter, parameter.name, parameter.initializer, context) :
parameter.initializer && parameter.name ? addDefaultValueAssignmentForInitializer(parameter, parameter.name, parameter.initializer, context) :
parameter;
}
function addDefaultValueAssignmentForBindingPattern(parameter: ParameterDeclaration, context: TransformationContext) {
const { factory } = context;
Debug.type<BindingPattern>(parameter.name);
context.addInitializationStatement(
factory.createVariableStatement(
/*modifiers*/ undefined,
@@ -391,6 +392,7 @@ namespace ts {
case SyntaxKind.Parameter:
Debug.type<ParameterDeclaration>(node);
Debug.type<BindingName>(node.name);
return factory.updateParameterDeclaration(node,
nodesVisitor(node.decorators, visitor, isDecorator),
nodesVisitor(node.modifiers, visitor, isModifier),
@@ -64,7 +64,7 @@ namespace ts.codefix {
const i = errorNode.parent.arguments.indexOf(errorNode);
if (i === -1) return undefined;
const name = (n.valueDeclaration as any as SignatureDeclaration).parameters[i].name;
if (isIdentifier(name)) return { source: errorNode, target: name };
if (name && isIdentifier(name)) return { source: errorNode, target: name };
}
else if (isPropertyAssignment(errorNode.parent) && isIdentifier(errorNode.parent.name) ||
isShorthandPropertyAssignment(errorNode.parent)) {
@@ -746,6 +746,7 @@ namespace ts.codefix {
if (isFunctionLikeDeclaration(funcNode)) {
if (funcNode.parameters.length > 0) {
const param = funcNode.parameters[0].name;
Debug.type<BindingName>(param);
name = getMappedBindingNameOrDefault(param);
}
}
@@ -167,7 +167,7 @@ namespace ts.codefix {
if (!(signature && signature.declaration && signature.parameters[argIndex])) return undefined;
const param = signature.parameters[argIndex].valueDeclaration;
if (!(param && isParameter(param) && isIdentifier(param.name))) return undefined;
if (!(param && isParameter(param) && param.name && isIdentifier(param.name))) return undefined;
const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent), checker.getTypeAtLocation(param), /* requireOptionalProperties */ false, /* matchDiscriminantProperties */ false));
if (!length(properties)) return undefined;
@@ -255,7 +255,7 @@ namespace ts.codefix {
isFixAll = false): void {
if (mayDeleteParameter(checker, sourceFile, parameter, sourceFiles, program, cancellationToken, isFixAll)) {
if (parameter.modifiers && parameter.modifiers.length > 0 &&
(!isIdentifier(parameter.name) || FindAllReferences.Core.isSymbolReferencedInFile(parameter.name, checker, sourceFile))) {
(!parameter.name || !isIdentifier(parameter.name) || FindAllReferences.Core.isSymbolReferencedInFile(parameter.name, checker, sourceFile))) {
parameter.modifiers.forEach(modifier => changes.deleteModifier(sourceFile, modifier));
}
else if (!parameter.initializer && isNotProvidedArguments(parameter, checker, sourceFiles)) {
@@ -331,7 +331,7 @@ namespace ts.codefix {
const index = parameters.indexOf(parameter);
Debug.assert(index !== -1, "The parameter should already be in the list");
return isFixAll ?
parameters.slice(index + 1).every(p => isIdentifier(p.name) && !p.symbol.isReferenced) :
parameters.slice(index + 1).every(p => p.name && isIdentifier(p.name) && !p.symbol.isReferenced) :
index === parameters.length - 1;
}
+1 -1
View File
@@ -121,7 +121,7 @@ namespace ts.codefix {
else {
Debug.assertNode(accessor, isSetAccessorDeclaration, "The counterpart to a getter should be a setter");
const parameter = getSetAccessorValueParameter(accessor);
const parameterName = parameter && isIdentifier(parameter.name) ? idText(parameter.name) : undefined;
const parameterName = parameter?.name && isIdentifier(parameter.name) ? idText(parameter.name) : undefined;
addClassElement(factory.createSetAccessorDeclaration(
/*decorators*/ undefined,
modifiers,
+5 -4
View File
@@ -229,6 +229,7 @@ namespace ts.codefix {
host: LanguageServiceHost,
cancellationToken: CancellationToken,
): void {
Debug.type<BindingName>(parameterDeclaration.name);
if (!isIdentifier(parameterDeclaration.name)) {
return;
}
@@ -287,7 +288,7 @@ namespace ts.codefix {
): void {
const param = firstOrUndefined(setAccessorDeclaration.parameters);
if (param && isIdentifier(setAccessorDeclaration.name) && isIdentifier(param.name)) {
if (param && isIdentifier(setAccessorDeclaration.name) && param.name && isIdentifier(param.name)) {
let type = inferTypeForVariableFromUsage(setAccessorDeclaration.name, program, cancellationToken);
if (type === program.getTypeChecker().getAnyType()) {
type = inferTypeForVariableFromUsage(param.name, program, cancellationToken);
@@ -344,7 +345,7 @@ namespace ts.codefix {
const inferences = mapDefined(parameterInferences, inference => {
const param = inference.declaration;
// only infer parameters that have (1) no type and (2) an accessible inferred type
if (param.initializer || getJSDocType(param) || !isIdentifier(param.name)) {
if (param.initializer || getJSDocType(param) || !param.name || !isIdentifier(param.name)) {
return;
}
const typeNode = inference.type && getTypeNodeIfAccessible(inference.type, param, program, host);
@@ -398,7 +399,7 @@ namespace ts.codefix {
return references && inferTypeFromReferences(program, references, cancellationToken).parameters(func) ||
func.parameters.map<ParameterInference>(p => ({
declaration: p,
type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : program.getTypeChecker().getAnyType()
type: p.name && isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : program.getTypeChecker().getAnyType()
}));
}
@@ -557,7 +558,7 @@ namespace ts.codefix {
types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex]));
}
}
if (isIdentifier(parameter.name)) {
if (parameter.name && isIdentifier(parameter.name)) {
const inferred = inferTypesFromReferencesSingle(getReferences(parameter.name, program, cancellationToken));
types.push(...(isRest ? mapDefined(inferred, checker.getElementTypeOfArrayType) : inferred));
}
+1 -1
View File
@@ -270,7 +270,7 @@ namespace ts.InlayHints {
const param = node.parameters[i];
const effectiveTypeAnnotation = getEffectiveTypeAnnotationNode(param);
if (effectiveTypeAnnotation) {
if (effectiveTypeAnnotation || !param.name) {
continue;
}
+2
View File
@@ -266,6 +266,7 @@ namespace ts.JsDoc {
if (!isFunctionLike(fn)) return [];
return mapDefined(fn.parameters, param => {
Debug.type<BindingName>(param.name);
if (!isIdentifier(param.name)) return undefined;
const name = param.name.text;
@@ -372,6 +373,7 @@ namespace ts.JsDoc {
function parameterDocComments(parameters: readonly ParameterDeclaration[], isJavaScriptFile: boolean, indentationStr: string, newLine: string): string {
return parameters.map(({ name, dotDotDotToken }, i) => {
Debug.type<BindingName>(name);
const paramName = name.kind === SyntaxKind.Identifier ? name.text : "param" + i;
const type = isJavaScriptFile ? (dotDotDotToken ? "{...any} " : "{any} ") : "";
return `${indentationStr} * @param ${type}${paramName}${newLine}`;
@@ -142,7 +142,7 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
}
function convertParameterToNamedTupleMember(p: ParameterDeclaration): NamedTupleMember {
Debug.assert(isIdentifier(p.name)); // This is checked during refactoring applicability checking
Debug.assert(p.name && isIdentifier(p.name)); // This is checked during refactoring applicability checking
const result = setTextRange(factory.createNamedTupleMember(
p.dotDotDotToken,
p.name,
@@ -209,7 +209,7 @@ ${newComment.split("\n").map(c => ` * ${c}`).join("\n")}
return;
}
const signatureDecls = decls as (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[];
if (some(signatureDecls, d => !!d.typeParameters || some(d.parameters, p => !!p.decorators || !!p.modifiers || !isIdentifier(p.name)))) {
if (some(signatureDecls, d => !!d.typeParameters || some(d.parameters, p => !!p.decorators || !!p.modifiers || !p.name || !isIdentifier(p.name)))) {
return;
}
const signatures = mapDefined(signatureDecls, d => checker.getSignatureFromDeclaration(d));
@@ -404,7 +404,7 @@ namespace ts.refactor.convertParamsToDestructuredObject {
const type = checker.getTypeAtLocation(parameterDeclaration);
if (!checker.isArrayType(type) && !checker.isTupleType(type)) return false;
}
return !parameterDeclaration.modifiers && !parameterDeclaration.decorators && isIdentifier(parameterDeclaration.name);
return !parameterDeclaration.modifiers && !parameterDeclaration.decorators && !!parameterDeclaration.name && isIdentifier(parameterDeclaration.name);
}
function isValidVariableDeclaration(node: Node): node is ValidVariableDeclaration {
@@ -412,7 +412,7 @@ namespace ts.refactor.convertParamsToDestructuredObject {
}
function hasThisParameter(parameters: NodeArray<ParameterDeclaration>): boolean {
return parameters.length > 0 && isThis(parameters[0].name);
return parameters.length > 0 && !!parameters[0].name && isThis(parameters[0].name);
}
function getRefactorableParametersLength(parameters: NodeArray<ParameterDeclaration>): number {
@@ -492,8 +492,8 @@ namespace ts.refactor.convertParamsToDestructuredObject {
/*questionToken*/ undefined,
thisParameter.type);
suppressLeadingAndTrailingTrivia(newThisParameter.name);
copyComments(thisParameter.name, newThisParameter.name);
suppressLeadingAndTrailingTrivia(newThisParameter.name!);
copyComments(thisParameter.name, newThisParameter.name!);
if (thisParameter.type) {
suppressLeadingAndTrailingTrivia(newThisParameter.type!);
copyComments(thisParameter.type, newThisParameter.type!);
+1 -1
View File
@@ -1291,7 +1291,7 @@ namespace ts.refactor.extractSymbol {
const firstParameter = firstOrUndefined(parameters);
// If the function signature has a this parameter and if the first defined parameter is not the this parameter, we must add it
// Note: If this parameter was already there, it would have been previously updated with the type if not type was present
if ((!firstParameter || (isIdentifier(firstParameter.name) && firstParameter.name.escapedText !== "this"))) {
if (!firstParameter || !firstParameter.name || (isIdentifier(firstParameter.name) && firstParameter.name.escapedText !== "this")) {
const thisType = checker.getTypeOfSymbolAtLocation(functionSignature.thisParameter, node);
parameters.splice(0, 0, factory.createParameterDeclaration(
/* decorators */ undefined,
+2
View File
@@ -540,6 +540,8 @@ namespace ts.textChanges {
}
}
else {
Debug.assert(node.parent.kind !== SyntaxKind.JSDocFunctionType);
Debug.type<BindingName | PropertyName>(node.name);
endNode = (node.kind === SyntaxKind.VariableDeclaration ? node.exclamationToken : node.questionToken) ?? node.name;
}