diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 312bbff48466e..96ee969adcf3a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5094,6 +5094,9 @@ namespace ts { if (parameterDeclaration && isRequiredInitializedParameter(parameterDeclaration)) { parameterType = getOptionalType(parameterType); } + if ((context.flags & NodeBuilderFlags.NoUndefinedOptionalParameterType) && parameterDeclaration && !isJSDocParameterTag(parameterDeclaration) && isOptionalUninitializedParameter(parameterDeclaration)) { + parameterType = getTypeWithFacts(parameterType, TypeFacts.NEUndefined); + } const parameterTypeNode = serializeTypeForDeclaration(context, parameterType, parameterSymbol, context.enclosingDeclaration, privateSymbolVisitor, bundledImports); const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags && parameterDeclaration && parameterDeclaration.modifiers ? parameterDeclaration.modifiers.map(factory.cloneNode) : undefined; @@ -36958,6 +36961,12 @@ namespace ts { hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); } + function isOptionalUninitializedParameter(parameter: ParameterDeclaration) { + return !!strictNullChecks && + isOptionalParameter(parameter) && + !parameter.initializer; + } + function isExpandoFunctionDeclaration(node: Declaration): boolean { const declaration = getParseTreeNode(node, isFunctionDeclaration); if (!declaration) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2472b302545cc..3d97aaaf85ab1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4160,6 +4160,7 @@ namespace ts { UseAliasDefinedOutsideCurrentScope = 1 << 14, // Allow non-visible aliases UseSingleQuotesForStringLiteralType = 1 << 28, // Use single quotes for string literal type NoTypeReduction = 1 << 29, // Don't call getReducedType + NoUndefinedOptionalParameterType = 1 << 30, // Do not add undefined to optional parameter type // Error handling AllowThisInObjectLiteral = 1 << 15, diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 12e8bb186453b..3c5669cb20c58 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -164,7 +164,7 @@ namespace ts.codefix { const program = context.program; const checker = program.getTypeChecker(); const scriptTarget = getEmitScriptTarget(program.getCompilerOptions()); - const flags = NodeBuilderFlags.NoTruncation | NodeBuilderFlags.SuppressAnyReturnType | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : 0); + const flags = NodeBuilderFlags.NoTruncation | NodeBuilderFlags.NoUndefinedOptionalParameterType | NodeBuilderFlags.SuppressAnyReturnType | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : 0); const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, flags, getNoopSymbolTrackerWithResolver(context)); if (!signatureDeclaration) { return undefined; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 83b03093da4b0..656b52d3154c7 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2232,6 +2232,7 @@ declare namespace ts { UseAliasDefinedOutsideCurrentScope = 16384, UseSingleQuotesForStringLiteralType = 268435456, NoTypeReduction = 536870912, + NoUndefinedOptionalParameterType = 1073741824, AllowThisInObjectLiteral = 32768, AllowQualifedNameInPlaceOfIdentifier = 65536, AllowAnonymousIdentifier = 131072, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index e85e4a8bf70b2..07e55e25d518d 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2232,6 +2232,7 @@ declare namespace ts { UseAliasDefinedOutsideCurrentScope = 16384, UseSingleQuotesForStringLiteralType = 268435456, NoTypeReduction = 536870912, + NoUndefinedOptionalParameterType = 1073741824, AllowThisInObjectLiteral = 32768, AllowQualifedNameInPlaceOfIdentifier = 65536, AllowAnonymousIdentifier = 131072, diff --git a/tests/cases/fourslash/codeFixClassImplementInterface_noUndefinedOnOptionalParameter.ts b/tests/cases/fourslash/codeFixClassImplementInterface_noUndefinedOnOptionalParameter.ts new file mode 100644 index 0000000000000..2d6626e50e898 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassImplementInterface_noUndefinedOnOptionalParameter.ts @@ -0,0 +1,23 @@ +/// + +////interface IFoo { +//// bar(x?: number | string): void; +////} +//// +////class Foo implements IFoo { +////} + +//https://github.com/microsoft/TypeScript/issues/39458 +verify.codeFix({ + description: [ts.Diagnostics.Implement_interface_0.message, "IFoo"], + newFileContent: +`interface IFoo { + bar(x?: number | string): void; +} + +class Foo implements IFoo { + bar(x?: string | number): void { + throw new Error("Method not implemented."); + } +}`, +});