From 5b7312fbbf4579d8daceaa0b7a816ac170130268 Mon Sep 17 00:00:00 2001 From: Jesse Trinity Date: Wed, 8 Jul 2020 14:46:26 -0700 Subject: [PATCH 1/3] remove undefined from optional parameter --- src/compiler/checker.ts | 15 ++++++++++++ src/compiler/types.ts | 1 + src/services/codefixes/helpers.ts | 2 +- ...nterface_noUndefinedOnOptionalParameter.ts | 23 +++++++++++++++++++ 4 files changed, 40 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 312bbff48466e..f230cad3ff7ac 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 = removeUndefinedType(parameterType); + } 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; @@ -18547,6 +18550,12 @@ namespace ts { type; } + function removeUndefinedType(type: Type): Type { + return getFalsyFlags(type) & TypeFlags.Undefined ? + filterType(type, t => !(getFalsyFlags(t) & TypeFlags.Undefined)) : + type; + } + function extractDefinitelyFalsyTypes(type: Type): Type { return mapType(type, getDefinitelyFalsyPartOfType); } @@ -36958,6 +36967,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/cases/fourslash/codeFixClassImplementInterface_noUndefinedOnOptionalParameter.ts b/tests/cases/fourslash/codeFixClassImplementInterface_noUndefinedOnOptionalParameter.ts new file mode 100644 index 0000000000000..beb1a6008fc9a --- /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."); + } +}`, +}); \ No newline at end of file From 08e3355a48062d2bcb0c9d957f7d9c7604b0729b Mon Sep 17 00:00:00 2001 From: Jesse Trinity Date: Wed, 8 Jul 2020 14:46:44 -0700 Subject: [PATCH 2/3] accept baselines --- tests/baselines/reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + 2 files changed, 2 insertions(+) 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, From 4214d8410a7c52d68e1d92119200d829504a3c8d Mon Sep 17 00:00:00 2001 From: Jesse Trinity Date: Thu, 9 Jul 2020 10:40:52 -0700 Subject: [PATCH 3/3] use getTypeWithFacts --- src/compiler/checker.ts | 8 +------- ...ssImplementInterface_noUndefinedOnOptionalParameter.ts | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f230cad3ff7ac..96ee969adcf3a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5095,7 +5095,7 @@ namespace ts { parameterType = getOptionalType(parameterType); } if ((context.flags & NodeBuilderFlags.NoUndefinedOptionalParameterType) && parameterDeclaration && !isJSDocParameterTag(parameterDeclaration) && isOptionalUninitializedParameter(parameterDeclaration)) { - parameterType = removeUndefinedType(parameterType); + parameterType = getTypeWithFacts(parameterType, TypeFacts.NEUndefined); } const parameterTypeNode = serializeTypeForDeclaration(context, parameterType, parameterSymbol, context.enclosingDeclaration, privateSymbolVisitor, bundledImports); @@ -18550,12 +18550,6 @@ namespace ts { type; } - function removeUndefinedType(type: Type): Type { - return getFalsyFlags(type) & TypeFlags.Undefined ? - filterType(type, t => !(getFalsyFlags(t) & TypeFlags.Undefined)) : - type; - } - function extractDefinitelyFalsyTypes(type: Type): Type { return mapType(type, getDefinitelyFalsyPartOfType); } diff --git a/tests/cases/fourslash/codeFixClassImplementInterface_noUndefinedOnOptionalParameter.ts b/tests/cases/fourslash/codeFixClassImplementInterface_noUndefinedOnOptionalParameter.ts index beb1a6008fc9a..2d6626e50e898 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterface_noUndefinedOnOptionalParameter.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterface_noUndefinedOnOptionalParameter.ts @@ -20,4 +20,4 @@ class Foo implements IFoo { throw new Error("Method not implemented."); } }`, -}); \ No newline at end of file +});