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

TS "Optional Properties" accepts "undefined" as a value when it shouldn't... #57479

Closed
denis-migdal opened this issue Feb 22, 2024 · 8 comments
Closed
Labels
Question An issue which isn't directly actionable in code

Comments

@denis-migdal
Copy link

πŸ”Ž Search Terms

Optional Properties accept undefined

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the documentation

⏯ Playground Link

Playground Link

πŸ’» Code

{
    type T = {
        DELETED?: string
    }

    let t1: T = {};
    console.log( Object.keys(t1) ); // []
    console.log( "DELETED" in t1 ); // false

    let t2: T = {DELETED: undefined}; // WRONG
    console.log( Object.keys(t2) ); // ["DELETED"]
    console.log( "DELETED" in t2 ); // true
}


{
    function foo(_a: number, _b?: string) {
        console.log(arguments);
    }

    console.log("test 1");
    foo(3); // [3]
    foo(3, undefined); // WRONG [3, undefined]
}

πŸ™ Actual behavior

In JS, there is a difference in behavior between properties that :

  1. doesn't exist (i.e. without value), and returns undefined when accessed.
  2. exists, with undefined as a value.

TS enables to declare a property optional with the "?" symbol (so normally corresponding to case 1.). However, this notation also allows case 2., which shouldn't be the case:

{
    type T = {
        DELETED?: string
    }

    let t1: T = {};
    console.log( Object.keys(t1) ); // []
    console.log( "DELETED" in t1 ); // false

    let t2: T = {DELETED: undefined}; // WRONG
    console.log( Object.keys(t2) ); // ["DELETED"]
    console.log( "DELETED" in t2 ); // true
}


{
    function foo(_a: number, _b?: string) {
        console.log(arguments);
    }

    console.log("test 1");
    foo(3); // [3]
    foo(3, undefined); // WRONG [3, undefined]
}

πŸ™‚ Expected behavior

When assigning a value to a type with optional fields, TS should forbid undefined values except if explicitly authorized :

type T1 = {field?: string};
type T2 = {field?: string|undefined};

let t1: T1 = {field: undefined} // should raise an error.
let t2: T2 = {field: undefined} // ok

Additional information about the issue

I get this would likely be a breaking change... but this is a bug.
Maybe a flag or a way to change TS behavior on this matter could help keeping retro-compatibility ?

@MartinJohns
Copy link
Contributor

MartinJohns commented Feb 22, 2024

This is working as intended and why exactOptionalPropertyTypes was introduced. This flag was introduced on TypeScript 4.4 (late 2021), so it's already a couple of years there.

And before the question comes up: this is intentionally not part of the strict flag due to the disruptive nature of this change. There are several flags available, I suggest you to check out the tsconfig reference.

@denis-migdal
Copy link
Author

denis-migdal commented Feb 22, 2024

This is working as intended and why exactOptionalPropertyTypes was introduced. This flag was introduced on TypeScript 4.4 (late 2021), so it's already a couple of years there.

I may have missed it (I think I started TS with 4.3)...
Is there some newsletter I could subscribe to to not miss changes ?

And before the question comes up: this is intentionally not part of the strict flag due to the disruptive nature of this change. There are several flags available, I suggest you to check out the tsconfig reference.

Then shouldn't it be an opt-out flag (when strict is specified), instead of an opt-in ?
With the error message presenting the opt-out possibility ?

I'm gonna re-read this page.

@MartinJohns
Copy link
Contributor

Is there some newsletter I could subscribe to to not miss changes ?

There's always a blog post for every release. They usually announce it on Twitter and Facebook too (probably more), but no newsletter. Choose your poison.

The website also contains the documentation for every release.

Then shouldn't it be an opt-out flag (when strict is specified), instead of an opt-in ?

#44421

@bgenia
Copy link

bgenia commented Feb 22, 2024

Is there some newsletter I could subscribe to to not miss changes ?

You can subscribe to github releases, they have blog posts attached

@denis-migdal
Copy link
Author

And before the question comes up: this is intentionally not part of the strict flag due to the disruptive nature of this change. There are several flags available, I suggest you to check out the tsconfig reference.

In the documentation, it isn't clear what that "strict mode family" flags are.
Are they only flags starting by "strict" ?

@denis-migdal
Copy link
Author

You can subscribe to github releases, they have blog posts attached

Oh thanks, good idea indeed.

@MartinJohns
Copy link
Contributor

In the documentation, it isn't clear what that "strict mode family" flags are.

The ones listed under "related". Each flag also mentions the default being true when strict is enabled.

@denis-migdal
Copy link
Author

The ones listed under "related". Each flag also mentions the default being true when strict is enabled.

Thanks, I didn't even noticed it.

With that, I think I can close this issue.

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Feb 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

4 participants