Preserve parameter types for optional parameters /fields with undefined in type and for required params with default value (#57484)

This commit is contained in:
Titian Cernicova-Dragomir
2024-02-29 09:42:26 -08:00
committed by GitHub
parent 2d70b57df4
commit e089896be4
8 changed files with 241 additions and 37 deletions
+10 -2
View File
@@ -48132,6 +48132,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return false;
}
function declaredParameterTypeContainsUndefined(parameter: ParameterDeclaration) {
if (!parameter.type) return false;
const type = getTypeFromTypeNode(parameter.type);
return containsUndefinedType(type);
}
function requiresAddingImplicitUndefined(parameter: ParameterDeclaration) {
return (isRequiredInitializedParameter(parameter) || isOptionalUninitializedParameterProperty(parameter)) && !declaredParameterTypeContainsUndefined(parameter);
}
function isRequiredInitializedParameter(parameter: ParameterDeclaration | JSDocParameterTag): boolean {
return !!strictNullChecks &&
!isOptionalParameter(parameter) &&
@@ -48525,8 +48534,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
isTopLevelValueImportEqualsWithEntityName,
isDeclarationVisible,
isImplementationOfOverload,
isRequiredInitializedParameter,
isOptionalUninitializedParameterProperty,
requiresAddingImplicitUndefined,
isExpandoFunctionDeclaration,
getPropertiesOfContainerFunction,
createTypeOfDeclaration,
+1 -2
View File
@@ -1091,8 +1091,7 @@ export const notImplementedResolver: EmitResolver = {
isLateBound: (_node): _node is LateBoundDeclaration => false,
collectLinkedAliases: notImplemented,
isImplementationOfOverload: notImplemented,
isRequiredInitializedParameter: notImplemented,
isOptionalUninitializedParameterProperty: notImplemented,
requiresAddingImplicitUndefined: notImplemented,
isExpandoFunctionDeclaration: notImplemented,
getPropertiesOfContainerFunction: notImplemented,
createTypeOfDeclaration: notImplemented,
+26 -31
View File
@@ -127,7 +127,6 @@ import {
isModuleDeclaration,
isOmittedExpression,
isPrivateIdentifier,
isPropertySignature,
isSemicolonClassElement,
isSetAccessorDeclaration,
isSourceFile,
@@ -708,7 +707,6 @@ export function transformDeclarations(context: TransformationContext) {
| FunctionDeclaration
| MethodDeclaration
| GetAccessorDeclaration
| SetAccessorDeclaration
| BindingElement
| ConstructSignatureDeclaration
| VariableDeclaration
@@ -727,46 +725,43 @@ export function transformDeclarations(context: TransformationContext) {
// Literal const declarations will have an initializer ensured rather than a type
return;
}
const shouldUseResolverType = node.kind === SyntaxKind.Parameter &&
(resolver.isRequiredInitializedParameter(node) ||
resolver.isOptionalUninitializedParameterProperty(node));
if (type && !shouldUseResolverType) {
const shouldAddImplicitUndefined = node.kind === SyntaxKind.Parameter && resolver.requiresAddingImplicitUndefined(node);
if (type && !shouldAddImplicitUndefined) {
return visitNode(type, visitDeclarationSubtree, isTypeNode);
}
if (!getParseTreeNode(node)) {
return type ? visitNode(type, visitDeclarationSubtree, isTypeNode) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
if (node.kind === SyntaxKind.SetAccessor) {
// Set accessors with no associated type node (from it's param or get accessor return) are `any` since they are never contextually typed right now
// (The inferred type here will be void, but the old declaration emitter printed `any`, so this replicates that)
return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
errorNameNode = node.name;
let oldDiag: typeof getSymbolAccessibilityDiagnostic;
if (!suppressNewDiagnosticContexts) {
oldDiag = getSymbolAccessibilityDiagnostic;
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(node);
}
if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) {
return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
let typeNode;
switch (node.kind) {
case SyntaxKind.Parameter:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.BindingElement:
case SyntaxKind.VariableDeclaration:
typeNode = resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldAddImplicitUndefined);
break;
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ConstructSignature:
case SyntaxKind.MethodSignature:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.CallSignature:
typeNode = resolver.createReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker);
break;
default:
Debug.assertNever(node);
}
if (
node.kind === SyntaxKind.Parameter
|| node.kind === SyntaxKind.PropertyDeclaration
|| node.kind === SyntaxKind.PropertySignature
) {
if (isPropertySignature(node) || !node.initializer) return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType));
return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType) || resolver.createTypeOfExpression(node.initializer, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
}
return cleanup(resolver.createReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
function cleanup(returnValue: TypeNode | undefined) {
errorNameNode = undefined;
if (!suppressNewDiagnosticContexts) {
getSymbolAccessibilityDiagnostic = oldDiag;
}
return returnValue || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
errorNameNode = undefined;
if (!suppressNewDiagnosticContexts) {
getSymbolAccessibilityDiagnostic = oldDiag!;
}
return typeNode ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
function isDeclarationAndNotVisible(node: NamedDeclaration) {
+1 -2
View File
@@ -5603,8 +5603,7 @@ export interface EmitResolver {
isLateBound(node: Declaration): node is LateBoundDeclaration;
collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined;
isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined;
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean;
requiresAddingImplicitUndefined(node: ParameterDeclaration): boolean;
isExpandoFunctionDeclaration(node: FunctionDeclaration): boolean;
getPropertiesOfContainerFunction(node: Declaration): Symbol[];
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;