From 8e9de9bed2e0170f7c43ef17b292cea29b46befb Mon Sep 17 00:00:00 2001 From: Jesse Trinity <42591254+jessetrinity@users.noreply.github.com> Date: Thu, 9 Jul 2020 11:17:18 -0700 Subject: [PATCH] Fix39458 (#39508) * remove undefined from optional parameter * accept baselines * use getTypeWithFacts --- src/compiler/checker.ts | 9 ++++++++ src/compiler/types.ts | 1 + src/services/codefixes/helpers.ts | 2 +- .../reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + ...nterface_noUndefinedOnOptionalParameter.ts | 23 +++++++++++++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/codeFixClassImplementInterface_noUndefinedOnOptionalParameter.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 312bbff4846..96ee969adcf 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 c0001d5b9fd..811b29abda6 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 12e8bb18645..3c5669cb20c 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 83b03093da4..656b52d3154 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 e85e4a8bf70..07e55e25d51 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 00000000000..2d6626e50e8 --- /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."); + } +}`, +});