From 2a921d4b33fdc774087366de920ffdd685b5e4fc Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 13 Jun 2017 11:31:51 -0700 Subject: [PATCH 1/3] Use checker for decl emit:optional parameter props Optional parameter properties create a property with a type that unions with undefined when strictNullChecks is on. This needs to be reflected in the generated declaration. --- src/compiler/declarationEmitter.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 007620ad510..8b4919e9da9 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -335,9 +335,12 @@ namespace ts { write(": "); // use the checker's type, not the declared type, - // for non-optional initialized parameters that aren't a parameter property + // for optional parameter properties + // and also for non-optional initialized parameters that aren't a parameter property + // these types may need to add `undefined`. const shouldUseResolverType = declaration.kind === SyntaxKind.Parameter && - resolver.isRequiredInitializedParameter(declaration as ParameterDeclaration); + (resolver.isRequiredInitializedParameter(declaration as ParameterDeclaration) || + (getModifierFlags(declaration) & ModifierFlags.ParameterPropertyModifier && resolver.isOptionalParameter(declaration as ParameterDeclaration))); if (type && !shouldUseResolverType) { // Write the type emitType(type); From 433a06d599be755be5d5e2d103abe82352bc97d6 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 13 Jun 2017 11:49:58 -0700 Subject: [PATCH 2/3] Add isOptionalUninitializedParameterProperty Improves declaration emit and code readability --- src/compiler/checker.ts | 8 ++++++++ src/compiler/declarationEmitter.ts | 2 +- src/compiler/types.ts | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 77c130b24de..88f8858be18 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23128,6 +23128,13 @@ namespace ts { !(getModifierFlags(parameter) & ModifierFlags.ParameterPropertyModifier); } + function isOptionalUninitializedParameterProperty(parameter: ParameterDeclaration) { + return strictNullChecks && + isOptionalParameter(parameter) && + !parameter.initializer && + !!(getModifierFlags(parameter) & ModifierFlags.ParameterPropertyModifier); + } + function getNodeCheckFlags(node: Node): NodeCheckFlags { return getNodeLinks(node).flags; } @@ -23337,6 +23344,7 @@ namespace ts { isDeclarationVisible, isImplementationOfOverload, isRequiredInitializedParameter, + isOptionalUninitializedParameterProperty, writeTypeOfDeclaration, writeReturnTypeOfSignatureDeclaration, writeTypeOfExpression, diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 8b4919e9da9..753080cc6a0 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -340,7 +340,7 @@ namespace ts { // these types may need to add `undefined`. const shouldUseResolverType = declaration.kind === SyntaxKind.Parameter && (resolver.isRequiredInitializedParameter(declaration as ParameterDeclaration) || - (getModifierFlags(declaration) & ModifierFlags.ParameterPropertyModifier && resolver.isOptionalParameter(declaration as ParameterDeclaration))); + resolver.isOptionalUninitializedParameterProperty(declaration as ParameterDeclaration)); if (type && !shouldUseResolverType) { // Write the type emitType(type); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 439091cece0..e9c004ec982 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2814,6 +2814,7 @@ namespace ts { collectLinkedAliases(node: Identifier): Node[]; isImplementationOfOverload(node: FunctionLikeDeclaration): boolean | undefined; isRequiredInitializedParameter(node: ParameterDeclaration): boolean; + isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean; writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; From 5780494ddbde0b4d825dc3bda6c08e79beaf736a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 13 Jun 2017 11:50:46 -0700 Subject: [PATCH 3/3] Test:declaration emit of optional parameter props --- .../declarationEmitParameterProperty.js | 24 +++++++++++++++++++ .../declarationEmitParameterProperty.symbols | 9 +++++++ .../declarationEmitParameterProperty.types | 9 +++++++ tests/baselines/reference/optionalMethods.js | 4 ++-- .../declarationEmitParameterProperty.ts | 6 +++++ 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/declarationEmitParameterProperty.js create mode 100644 tests/baselines/reference/declarationEmitParameterProperty.symbols create mode 100644 tests/baselines/reference/declarationEmitParameterProperty.types create mode 100644 tests/cases/compiler/declarationEmitParameterProperty.ts diff --git a/tests/baselines/reference/declarationEmitParameterProperty.js b/tests/baselines/reference/declarationEmitParameterProperty.js new file mode 100644 index 00000000000..262222e3c68 --- /dev/null +++ b/tests/baselines/reference/declarationEmitParameterProperty.js @@ -0,0 +1,24 @@ +//// [declarationEmitParameterProperty.ts] +export class Foo { + constructor(public bar?: string) { + } +} + + +//// [declarationEmitParameterProperty.js] +"use strict"; +exports.__esModule = true; +var Foo = (function () { + function Foo(bar) { + this.bar = bar; + } + return Foo; +}()); +exports.Foo = Foo; + + +//// [declarationEmitParameterProperty.d.ts] +export declare class Foo { + bar: string | undefined; + constructor(bar?: string | undefined); +} diff --git a/tests/baselines/reference/declarationEmitParameterProperty.symbols b/tests/baselines/reference/declarationEmitParameterProperty.symbols new file mode 100644 index 00000000000..d9e88e52cb0 --- /dev/null +++ b/tests/baselines/reference/declarationEmitParameterProperty.symbols @@ -0,0 +1,9 @@ +=== tests/cases/compiler/declarationEmitParameterProperty.ts === +export class Foo { +>Foo : Symbol(Foo, Decl(declarationEmitParameterProperty.ts, 0, 0)) + + constructor(public bar?: string) { +>bar : Symbol(Foo.bar, Decl(declarationEmitParameterProperty.ts, 1, 14)) + } +} + diff --git a/tests/baselines/reference/declarationEmitParameterProperty.types b/tests/baselines/reference/declarationEmitParameterProperty.types new file mode 100644 index 00000000000..3adfecf0c75 --- /dev/null +++ b/tests/baselines/reference/declarationEmitParameterProperty.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/declarationEmitParameterProperty.ts === +export class Foo { +>Foo : Foo + + constructor(public bar?: string) { +>bar : string | undefined + } +} + diff --git a/tests/baselines/reference/optionalMethods.js b/tests/baselines/reference/optionalMethods.js index d219466c562..2abcd209277 100644 --- a/tests/baselines/reference/optionalMethods.js +++ b/tests/baselines/reference/optionalMethods.js @@ -131,12 +131,12 @@ interface Foo { } declare function test1(x: Foo): void; declare class Bar { - d: number; + d: number | undefined; e: number; a: number; b?: number; c?: number | undefined; - constructor(d?: number, e?: number); + constructor(d?: number | undefined, e?: number); f(): number; g?(): number; h?(): number; diff --git a/tests/cases/compiler/declarationEmitParameterProperty.ts b/tests/cases/compiler/declarationEmitParameterProperty.ts new file mode 100644 index 00000000000..107d192fe88 --- /dev/null +++ b/tests/cases/compiler/declarationEmitParameterProperty.ts @@ -0,0 +1,6 @@ +// @strictNullChecks: true +// @declaration: true +export class Foo { + constructor(public bar?: string) { + } +}