Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add undefined to declaration of constructor parameter property with… #50494

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

Zzzen
Copy link
Contributor

@Zzzen Zzzen commented Aug 28, 2022

… default

Fixes #48547

@typescript-bot typescript-bot added the For Backlog Bug PRs that fix a backlog bug label Aug 28, 2022
@Zzzen Zzzen marked this pull request as draft August 28, 2022 11:05
@Zzzen Zzzen marked this pull request as ready for review August 28, 2022 17:02
Copy link
Member

@DanielRosenwasser DanielRosenwasser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to accept the new baselines and make sure the old ones are gone.

tests/cases/compiler/declarationEmitParameterProperty2.ts Outdated Show resolved Hide resolved
@sandersn sandersn added this to Not started in PR Backlog Sep 12, 2022
Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like it is working against existing machinery for tracking strict null checks and emitting type declarations. @weswigham can you take a look too?

src/compiler/checker.ts Outdated Show resolved Hide resolved
@@ -43537,7 +43536,7 @@ namespace ts {
flags |= NodeBuilderFlags.AllowUniqueESSymbolType;
}
if (addUndefined) {
type = getOptionalType(type);
type = getOptionalType(type, /*isProperty*/ undefined, /*ignoreStrictNullChecks*/ true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a better way to fix this would be to temporarily set strictNullChecks = true and then run getOptionalType, then reset it afterward. @weswigham does that make sense to you? Or can you suggest a different way entirely?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any and every initialized parameter property needs a ? if it's a trailing parameter. This is something that the transformer needs to check, beyond the resolver.isOptionalParameter check it already does. Once that's handled, rather than doing anything strict-null-check-dependent, I'd keep it syntactic, and likely in the declaration emitter. If the parameter doesn't get a ? (because it has a required parameter after it), then we add | undefined to the type, regardless of mode, provided the existing serialized type doesn't contain it. (We don't need/want to do this extra explicit undefined addition for stuff with the ? so we can better strict optional property check them, I think.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@weswigham Very insightful! Should just think outside the box. Now the implementation is simplified and several bugs are fixed.

!isOptionalParameter(parameter) &&
!isJSDocParameterTag(parameter) &&
!!parameter.initializer &&
!hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier);
(!checkSyntacticModifier || !hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read this as: when checkSyntacticModifier=false, we are supposed to treat all parameters with initialisers as required, even if they are parameter properties. (normally parameter properties with initialisers are optional.)

Why? I kind of understand the original rule: parameter properties with initialisers don't need an argument, although I don't understand why they're special. But I don't understand why they now need an exemption. I guess it's so that the declaration emitter can distinguish between the emitted parameter (needs to add | undefined) and the property declaration (needs no undefined).

PR Backlog automation moved this from Not started to Waiting on author Sep 21, 2022
@@ -43537,7 +43536,7 @@ namespace ts {
flags |= NodeBuilderFlags.AllowUniqueESSymbolType;
}
if (addUndefined) {
type = getOptionalType(type);
type = getOptionalType(type, /*isProperty*/ undefined, /*ignoreStrictNullChecks*/ true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any and every initialized parameter property needs a ? if it's a trailing parameter. This is something that the transformer needs to check, beyond the resolver.isOptionalParameter check it already does. Once that's handled, rather than doing anything strict-null-check-dependent, I'd keep it syntactic, and likely in the declaration emitter. If the parameter doesn't get a ? (because it has a required parameter after it), then we add | undefined to the type, regardless of mode, provided the existing serialized type doesn't contain it. (We don't need/want to do this extra explicit undefined addition for stuff with the ? so we can better strict optional property check them, I think.)

@Zzzen Zzzen force-pushed the decl-emit-for-parameter-property branch from fa1542c to 40fdbe6 Compare December 18, 2022 12:20
@Zzzen Zzzen requested a review from weswigham December 19, 2022 15:16
@sandersn sandersn moved this from Waiting on author to Waiting on reviewers in PR Backlog Mar 10, 2023
Copy link
Member

@weswigham weswigham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this approach looks pretty workable, though I think maybe we also need to consider exactOptionalPropertyTypes behavior when generating the type nodes, too. Or maybe we just need to reuse input nodes more. Most of these baselines look good, it's just the change to the non-strict parameter property declaration emit that worries me.

@@ -248,7 +248,7 @@ export declare class ConstructorWithPrivateParameterProperty {
constructor(x: string);
}
export declare class ConstructorWithOptionalParameterProperty {
x?: string;
x?: string | undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I think we'd still rather this not add undefined, since the original declaration didn't have undefined, for the sake of exactOptionalPropertyTypes. Maybe we need to consider that flag's logic during serialization as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my surprise, the implementation was simpler than I expected.

PR Backlog automation moved this from Waiting on reviewers to Waiting on author Mar 15, 2023
@sandersn sandersn moved this from Waiting on author to Waiting on reviewers in PR Backlog Mar 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Status: Waiting on reviewers
PR Backlog
  
Waiting on reviewers
5 participants