Skip to content

exactOptionalPropertyTypes does not apply to constructor parameters #48952

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

Closed
sxxov opened this issue May 4, 2022 · 2 comments
Closed

exactOptionalPropertyTypes does not apply to constructor parameters #48952

sxxov opened this issue May 4, 2022 · 2 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@sxxov
Copy link

sxxov commented May 4, 2022

Bug Report

🔎 Search Terms

exact, optional, property, types, constructor, parameters, arguments, undefined, ?

🕗 Version & Regression Information

4.4 & above (including the latest nightly, v4.7.0-dev.20220504)

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about optional class members
  • I was unable to test this on prior versions because exactOptionalPropertyTypes was added in 4.4

⏯ Playground Link

Playground link with relevant code

💻 Code

class A {
    public prop?: 'bar';

    constructor(
        public ctorProp?: 'foo',
    ) {}
}

// correctly throws an error
new A().prop = undefined;

// incorrectly(?) doesn't throw an error, even though a developer might expect it to
new A().ctorProp = undefined;

🙁 Actual behavior

Only the property which is defined on the class itself reports as an error, when undefined is assigned to them.

// correctly throws an error
new A().prop = undefined;

// incorrectly(?) doesn't throw an error, even though a developer might expect it to
new A().ctorProp = undefined;

The types on the class is incorrect as well.

// 'bar'
new A().prop;

// 'bar' | undefined
new A().ctorProp;

In the JS emitted, one can see that an assignment is made regardless if a parameter is passed into it.

class A {
    ctorProp;
    prop;
    constructor(ctorProp) {
        this.ctorProp = ctorProp;
    }
}

While typescript's error is consistent with the outputted code, this may not be the expected behaviour when exactOptionalPropertyTypes is enabled. Related: #47350.

🙂 Expected behavior

Properties defined in both styles should report an error, when undefined is assigned to them.

// correctly throws an error
new A().prop = undefined;

// correctly throws an error
new A().ctorProp = undefined;

The types on the class should have their behaviours matched as well.

// 'bar'
new A().prop;

// 'bar'
new A().ctorProp;

The JS emitted, while I'm not sure how viable it is, should only assign when a parameter is passed in.

class A {
    ctorProp;
    prop;
    constructor(ctorProp) {
        // if target is >= es2021
        this.ctorProp ??= ctorProp;

        // else
        // if (0 in arguments) this.ctorProp = ctorProp;
    }
}
@MartinJohns
Copy link
Contributor

IMO this is a duplicate of #44548. Or at the very least it would first require #44548.

exactOptionalPropertyTypes does not apply for parameters. You can pass undefined as a value, and then you'd require additional logic to be emitted - something that TypeScript opted out quite a while ago.

@andrewbranch andrewbranch added the Working as Intended The behavior described is the intended behavior; this is not a bug label May 4, 2022
@sxxov
Copy link
Author

sxxov commented May 4, 2022

Oops, could not find #44548 due to the setting being changed from --strictOptionalProperties to --exactOptionalPropertyTypes.

Though I don't think it's 100% a duplicate, I understand the viewpoint & don't believe this issue can be fixed without additional logic. It still is a big thorn in DX though imo when using the ctor params pattern.

@sxxov sxxov closed this as completed May 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

3 participants