-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Destructuring causes error for null/undefined properties #6784
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
Comments
This is just the ES6 destructuring behavior; we don't use type system data to change the runtime behavior. That said, it's a bad idea to use a property of an optional property as part of a destructuring, and we should probably consider this an error. |
I agree that it should be an error if not handled elsewhere. Destructuring assignment is a great way to clear out boilerplate code, which makes it easier to focus on domain-specific logic. It feels crippled without support for optional parameters (which are a TypeScript feature, not an ES feature). I feel like if we extend destructuring with optional annotations - in a manner entirely consistent with conditional function parameters - it greatly enhances the utility and applicability of destructuring. Strawman: interface AjaxOptions {
timeout?: number,
onComplete?: () => void;
onSuccess?: () => void;
onError?: () => void;
}
type AjaxParams = { url: string, method?: string, body?: string, data: string, options?: AjaxOptions };
function send( { url, method = 'GET', data?, options?: { timeout, onComplete, onSuccess, onError } }: AjaxParams ) {
// do stuff
} The code in the body of the example can now check whether Basically, use the same Using the destructuring assignment expression itself here instead of the metadata means that you must opt-in to this behavior. It is not inferred from the type definition. |
Accepting PRs. Any property destructuring must be non-optional or have a default |
@RyanCavanaugh Just to be clear, are you accepting PRs to make Edit: Never mind, I see from the linked issue that it's the former. |
I already said about this problem in #6125. This issue is duplicate. |
we are accepting PRs for flagging destructuring into a optional property as an error. We still do not want to do any type directed emit. |
This implies that in cases where I know (because of program context) that the optional property is present in my object, I won't be able to destructure? interface X { a?: { b: number } };
let x: X;
if (x.a) { // or some other domain rule that guarantees me 'a' is defined
let { a: { b } } = x; // error: "a" is optional ?
} I don't have any use for such code, just pointing out the possible implications if it becomes an error. |
|
@mhegazy Yes but this was just for illustration. So if we forbid destructing an optional member, should we be able to do this? let { a!: { b } } = x; Thinking about it, I guess it makes sense. |
I'd be concerned about throwing a compile error when trying to destructure from an optional property. A common case for me is destructuring a react components state object. In my state interface I have all properties marked as optional so that I can call I also have optional properties on interfaces for objects I get from and pass to the API. I know that when I get the object it is fully populated, but when sending a PATCH I want to be able to send just the dirty fields while still having a type check that I'm not including any fields not on the object. Even with all optional properties these interfaces provide value by making sure I spell my properties right with type checking... but this compile error would break some of my code. |
@TheTedAdams I believe |
These are good points and lead me to believe we should make this change contingent on #7355. I'll reraise for discussion. |
I think you also have the problem when destructuring arrays. const [a, b, c] = ''.split('') TypeScript will consider all three variables to be |
@pauldijou Pretty sure that's unrelated to this issue (this issue is about nested destructuring that can cause a runtime error). See #9235 for index signatures. |
The sample code in this issue correctly has a compile error now. Is this resolved? |
@Andy-MS can we have a syntax to indicate something nullable is actually set and so the error should be ignored? See my previous comment #6784 (comment) |
what about doing it same way as c# ?. operator? some random blog with explanation var property = some?.nested?.property?.name;
// with is equivallent to:
var property = some == null ? null
: some.nested == null ? null
: some.nested.property == null ? null
: some.nested.property.name; in ts this would be current syntax var some: { nested?: { property?: { name: string } } } = ...;
var { nested: { property: { name } } } = some; // name has type string | undefined transpiled into: var property = ['nested', 'property', 'name'].reduce((obj, prop) => obj && obj[prop], some); not sure how to handle multiple nested variables ... |
What's the current status of this? |
In strict-mode should be invalid. Why only at runtime I get aTypeError: Cannot read property 'toUpperCase' of undefined ? Thought in strict-mode it is guaranteed that values are not null or undefined implicitly :((( |
This code will dramatically fail because destructuring an const f1 = (something: string): { foo: string } | undefined => {
return something == 'foo' ? { foo: 'bar' } : undefined;
};
const { foo } = f1('bar'); Shouldn't TypeScript throw an error if it's the case? Happy to put my hands in TS' code if we have agreement on this expected behaviour :) |
@sroze it does error if you have strict null checks on. When you run in sloppy mode, it behaves as expected and does not error. |
Ran into the same problem. Any fixes? |
The following code:
transpiles to:
instead of the (arguably) preferable:
The transpiled code does not check for the presence of optional property
foo
in theBar
interface. This leads to an error at invocation.I can see three possible solutions:
E.g.
The text was updated successfully, but these errors were encountered: