Skip to content

Commit 85f60d9

Browse files
Preserve parameter types unless we absolutely must resolve them.
1 parent 3e04102 commit 85f60d9

File tree

5 files changed

+47
-53
lines changed

5 files changed

+47
-53
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48219,6 +48219,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4821948219
return false;
4822048220
}
4822148221

48222+
function declaredParameterTypeContainsUndefined(parameter: ParameterDeclaration) {
48223+
if (!parameter.type) return false;
48224+
const type = getTypeFromTypeNode(parameter.type);
48225+
return type === undefinedType || !!(type.flags & TypeFlags.Union) && !!((type as UnionType).types[0].flags & TypeFlags.Undefined);
48226+
}
48227+
function requiresAddingImplicitUndefined(parameter: ParameterDeclaration) {
48228+
return (isRequiredInitializedParameter(parameter) || isOptionalUninitializedParameterProperty(parameter)) && !declaredParameterTypeContainsUndefined(parameter);
48229+
}
48230+
4822248231
function isRequiredInitializedParameter(parameter: ParameterDeclaration | JSDocParameterTag): boolean {
4822348232
return !!strictNullChecks &&
4822448233
!isOptionalParameter(parameter) &&
@@ -48612,8 +48621,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4861248621
isTopLevelValueImportEqualsWithEntityName,
4861348622
isDeclarationVisible,
4861448623
isImplementationOfOverload,
48615-
isRequiredInitializedParameter,
48616-
isOptionalUninitializedParameterProperty,
48624+
requiresAddingImplicitUndefined,
4861748625
isExpandoFunctionDeclaration,
4861848626
getPropertiesOfContainerFunction,
4861948627
createTypeOfDeclaration,

src/compiler/emitter.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,8 +1161,7 @@ export const notImplementedResolver: EmitResolver = {
11611161
isLateBound: (_node): _node is LateBoundDeclaration => false,
11621162
collectLinkedAliases: notImplemented,
11631163
isImplementationOfOverload: notImplemented,
1164-
isRequiredInitializedParameter: notImplemented,
1165-
isOptionalUninitializedParameterProperty: notImplemented,
1164+
requiresAddingImplicitUndefined: notImplemented,
11661165
isExpandoFunctionDeclaration: notImplemented,
11671166
getPropertiesOfContainerFunction: notImplemented,
11681167
createTypeOfDeclaration: notImplemented,

src/compiler/transformers/declarations.ts

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ import {
128128
isModuleDeclaration,
129129
isOmittedExpression,
130130
isPrivateIdentifier,
131-
isPropertySignature,
132131
isSemicolonClassElement,
133132
isSetAccessorDeclaration,
134133
isSourceFile,
@@ -722,7 +721,6 @@ export function transformDeclarations(context: TransformationContext) {
722721
| FunctionDeclaration
723722
| MethodDeclaration
724723
| GetAccessorDeclaration
725-
| SetAccessorDeclaration
726724
| BindingElement
727725
| ConstructSignatureDeclaration
728726
| VariableDeclaration
@@ -741,46 +739,43 @@ export function transformDeclarations(context: TransformationContext) {
741739
// Literal const declarations will have an initializer ensured rather than a type
742740
return;
743741
}
744-
const shouldUseResolverType = node.kind === SyntaxKind.Parameter &&
745-
(resolver.isRequiredInitializedParameter(node) ||
746-
resolver.isOptionalUninitializedParameterProperty(node));
747-
if (type && !shouldUseResolverType) {
742+
const shouldAddImplicitUndefined = node.kind === SyntaxKind.Parameter && resolver.requiresAddingImplicitUndefined(node);
743+
if (type && !shouldAddImplicitUndefined) {
748744
return visitNode(type, visitDeclarationSubtree, isTypeNode);
749745
}
750-
if (!getParseTreeNode(node)) {
751-
return type ? visitNode(type, visitDeclarationSubtree, isTypeNode) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
752-
}
753-
if (node.kind === SyntaxKind.SetAccessor) {
754-
// 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
755-
// (The inferred type here will be void, but the old declaration emitter printed `any`, so this replicates that)
756-
return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
757-
}
746+
758747
errorNameNode = node.name;
759748
let oldDiag: typeof getSymbolAccessibilityDiagnostic;
760749
if (!suppressNewDiagnosticContexts) {
761750
oldDiag = getSymbolAccessibilityDiagnostic;
762751
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(node);
763752
}
764-
if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) {
765-
return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
766-
}
767-
if (
768-
node.kind === SyntaxKind.Parameter
769-
|| node.kind === SyntaxKind.PropertyDeclaration
770-
|| node.kind === SyntaxKind.PropertySignature
771-
) {
772-
if (isPropertySignature(node) || !node.initializer) return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType));
773-
return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType) || resolver.createTypeOfExpression(node.initializer, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
753+
let typeNode;
754+
switch (node.kind) {
755+
case SyntaxKind.Parameter:
756+
case SyntaxKind.PropertySignature:
757+
case SyntaxKind.PropertyDeclaration:
758+
case SyntaxKind.BindingElement:
759+
case SyntaxKind.VariableDeclaration:
760+
typeNode = resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldAddImplicitUndefined);
761+
break;
762+
case SyntaxKind.FunctionDeclaration:
763+
case SyntaxKind.ConstructSignature:
764+
case SyntaxKind.MethodSignature:
765+
case SyntaxKind.MethodDeclaration:
766+
case SyntaxKind.GetAccessor:
767+
case SyntaxKind.CallSignature:
768+
typeNode = resolver.createReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker);
769+
break;
770+
default:
771+
Debug.assertNever(node);
774772
}
775-
return cleanup(resolver.createReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker));
776773

777-
function cleanup(returnValue: TypeNode | undefined) {
778-
errorNameNode = undefined;
779-
if (!suppressNewDiagnosticContexts) {
780-
getSymbolAccessibilityDiagnostic = oldDiag;
781-
}
782-
return returnValue || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
774+
errorNameNode = undefined;
775+
if (!suppressNewDiagnosticContexts) {
776+
getSymbolAccessibilityDiagnostic = oldDiag!;
783777
}
778+
return typeNode ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
784779
}
785780

786781
function isDeclarationAndNotVisible(node: NamedDeclaration) {

src/compiler/types.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5699,8 +5699,7 @@ export interface EmitResolver {
56995699
isLateBound(node: Declaration): node is LateBoundDeclaration;
57005700
collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined;
57015701
isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined;
5702-
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
5703-
isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean;
5702+
requiresAddingImplicitUndefined(node: ParameterDeclaration): boolean;
57045703
isExpandoFunctionDeclaration(node: FunctionDeclaration): boolean;
57055704
getPropertiesOfContainerFunction(node: Declaration): Symbol[];
57065705
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;

tests/baselines/reference/verbatim-declarations-parameters.js

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,21 @@ exports.foo1 = foo1;
5454

5555

5656
//// [verbatim-declarations-parameters.d.ts]
57+
type Map = {} & {
58+
[P in string]: any;
59+
};
60+
type MapOrUndefined = Map | undefined | "dummy";
5761
export declare class Foo {
58-
reuseTypeNode?: {
59-
[x: string]: any;
60-
} | undefined;
61-
reuseTypeNode2?: {
62-
[x: string]: any;
63-
} | undefined;
62+
reuseTypeNode?: Map | undefined;
63+
reuseTypeNode2?: Exclude<MapOrUndefined, "dummy">;
6464
resolveType?: {
6565
[x: string]: any;
6666
} | undefined;
67-
constructor(reuseTypeNode?: {
68-
[x: string]: any;
69-
} | undefined, reuseTypeNode2?: {
70-
[x: string]: any;
71-
} | undefined, resolveType?: {
67+
constructor(reuseTypeNode?: Map | undefined, reuseTypeNode2?: Exclude<MapOrUndefined, "dummy">, resolveType?: {
7268
[x: string]: any;
7369
} | undefined);
7470
}
75-
export declare function foo1(reuseTypeNode: {
76-
[x: string]: any;
77-
} | undefined, reuseTypeNode2: {
78-
[x: string]: any;
79-
} | undefined, resolveType: {
71+
export declare function foo1(reuseTypeNode: Map | undefined, reuseTypeNode2: Exclude<MapOrUndefined, "dummy">, resolveType: {
8072
[x: string]: any;
8173
} | undefined, requiredParam: number): void;
74+
export {};

0 commit comments

Comments
 (0)