Skip to content

TS doesn't allow optional param destructing in spite of having a default value assigned #35160

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
jalooc opened this issue Nov 17, 2019 · 6 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@jalooc
Copy link

jalooc commented Nov 17, 2019

TypeScript Version: 3.7.2

Search Terms:
default optional parameters destructing

Code

type F = {
  (foo?: { bar?: {}}): void
}

const f: F = ({ bar } = {}) => {

}

const g: F = (foo = {}) => {
  const { bar } = foo
}

Expected behavior:
Both functions: f and g should be compiled without errors. foo is optional, but it's also provided a default value; same with bar. Therefore both foo and bar are in fact never undefined. Btw this also works in vanilla js, tested with all sorts of parameter types.

Actual behavior:
TS error is thrown for the f function's destructuring of the optional param:

Property 'bar' does not exist on type '{ bar?: {} | undefined; } | undefined'.(2339)

This error does sound right, but shouldn't occur taking into consideration those three facts:

  1. If foo is undefined (= not passed as an argument to the function), the default value kicks in, so foo becomes {}. It's safe to access bar then.
  2. Function g does exactly the same logic as f, yet it doesn't fail compilation.
  3. It's safe to access bar in vanilla js.

Playground Link:
http://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=11&pc=2#code/C4TwDgpgBAYlC8UDeAoKUAUAzA9jg-AFzJQBGAhgE5HIC+tAlMQG44CWAJirSigMY4AdgGdgULMTiIMSMlSi0EdBggB8yXj35DRUAOaSl2PEqSM1G9AJFjZFSgqW4c3IA

@RyanCavanaugh
Copy link
Member

TypeScript is doing what you told it to do: you wrote bar without any annotation, so it was assumed to be a required destructuring.

You can write this instead if you meant it to be optional:

const f: F = ({ bar }: { bar?: {} | undefined } = {}) => {

}

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Nov 26, 2019
@jalooc
Copy link
Author

jalooc commented Nov 27, 2019

@RyanCavanaugh bar is typed withing the F type. Isn't that enough?

Besides ? implies it can be undefined. Isn't adding undefined type to the union for an optional param a no-op?

@RyanCavanaugh
Copy link
Member

Contextual typing can change the type of a parameter, but can't change its optionality. | undefined is implied by optionality, but not vice versa.

@jalooc
Copy link
Author

jalooc commented Nov 27, 2019

@RyanCavanaugh Exactly, so adding | undefined to bar in my example doesn't change anything since bar is optional. I don't see how this is relevant to my issue anyway. What do you mean by:

you wrote bar without any annotation

? It's type is derived from F.

@typescript-bot
Copy link
Collaborator

This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.

@jalooc
Copy link
Author

jalooc commented Dec 2, 2019

@typescript-bot It's still not clear to me whether this really is a question or a bug, as my last comment hasn't been answered. Please don't close until there's a unanimous conclusion about it.

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

3 participants