question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Further refine the error messages around allowing normal JavaScript property gets

See original GitHub issue

This issue is tracking problems that come up due to allowing normal JavaScript property lookup to work with computed properties.

Context

We are in the process of landing a change that will allow you to use normal property lookups to get properties defined as computed properties in Ember.

In practice, what this means is that, in most cases (more later) you will be able to drop .get('key') and replace it with .key.

However, there are a handful of small historical issues that could make the transition a little more messy. If you landed on this issue, chances are you encountered a warning from Ember that you encountered one of these historical issues.

Computed Properties used to be directly on the prototype

Until Ember 3.0, internal implementation details of Ember caused computed properties to be directly present on objects, so if you didn’t use .get(), you would see the internal “Ember descriptor” representing the computed property (a private API).

This internal implementation detail was never intended to be a public (or even intimate) API.

This internal implementation detail has now changed and the (still private) “descriptor” object has been relocated to the object’s “meta” (also a private API). This allows us to make normal property lookup work, and in general, very few people were relying on the presence of this internal descriptor.

If you encountered an error related to this problem, you are probably using an addon that relies on this now-defunct private implementation detail, and your best bet is to follow the instructions in the error message (and ask for help in #dev-ember).

Ember Proxies are tricky

Secondly, since the new behavior relies on using defineProperty, it does not allow users of Ember proxies to stop using .get().

Previously, since all Ember objects required you to use .get() to access properties, you could uniformly use .get() in your code and never need to worry about whether an object was an Ember proxy.

However, now that you can use normal property access for computed properties, Ember proxies are special. If an object is implemented using an Ember proxy, it should advertise itself as requiring .get() to access its proxied properties.

This is analogous to other libraries in the JavaScript ecosystem, such as immutable.js, that expose an API that is different from normal JS property access patterns.

Since proxies are relatively rare in Ember compared to property access on other Ember objects, emberjs/rfcs#281 (now merged) felt that the cost of losing consistent property access (everyone types .get() everywhere, so you don’t need to know when an object is “special”) was worth the benefit of normally not needing to use .get().

During the transition, we are worried that people will accidentally migrate some .get()s on Ember proxies to regular property access, so we added an assertion to the code that fires if:

  • you use a normal property get on an Ember proxy
  • the property is not present on the object itself
  • unknownProperty returns a value other than undefined

(this development-mode assertion is implemented using ES2015 proxies, which are not yet present on all supported browsers, but will cover the browsers people typically use for development)

For the most part, this avoids the vast majority of mistakes but it does introduce a possible problem with code that “probes” objects to discover whether they implement protocols.

Here’s what I mean by “probing” code:

if (obj.toJSON) {
  return obj.toJSON();
}

A more resilient way to write this code would be:

if ('toJSON' in obj && typeof obj.toJSON === 'function') {
  return obj.toJSON();
}

Unfortunately, apps are not always in control of the probing code (which could come from test frameworks, generic serialization logic, etc.).

Notably, “probing” code is only a problem if:

  • an Ember proxy finds its way to the probing code
  • the property is not present on the object itself (not true about toString, which is usually a real property of the Ember proxy itself)
  • and this is the important part: unknownProperty returns something other than undefined

It’s definitely possible that an Ember proxy could return some object for every possible property, and that some probing code checks for a protocol that’s not usually present on the wrapper object (like toString), which would trigger the assertion inappropriately.

This problem comes up now because probing code previously would only look at properties of the wrapper proxy object, but now, in order to provide good errors for people accidentally removing .get() that they shouldn’t have, normal property accesses on Ember proxies become sensitive to the behavior of unknownProperty.

Again, the correct mental model going forward is that these objects (most notably the values returned from relationships in Ember Data) are now special objects and require a non-standard API, but the process of migration introduces this ambiguity.

If you got this error and didn’t expect it, please reply to this issue with information about what happened so we have help improve the error message with more further advice and workarounds.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:3
  • Comments:14 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
pixelhandlercommented, Sep 21, 2018

@wycats do you know if any effort has been done to further refine the errors?

Sounds like we need to provide a good warning message for the scenario where dot access was attempted for a proxy object ?

Since Ember 3.1, this is usually fine as you no longer need to use .get() to access computed properties. However, in this case, the object in question is a special kind of Ember object (a proxy). Therefore, it is still necessary to use .get('length') in this case.

Also need to be sure this is well understood ^

Thanks @yininge for pointing out we need to revisit this one 😃

Perhaps instead of You attempted to access the inspect property (of <DS.Errors:ember460>) we should identify that a proxy object was involved and explain that .get() is required ?

Per the 3.1 blog post we have instruction on when to use .get().

If you are calling get with a chained path. For example in this.get('a.b.c') if b is undefined the return value is undefined. Converting this to this.a.b.c when b is undefined would instead raise an exception.

If your object is using unknownProperty you must continue to use get. Using an ES5 getter on an object with unknownProperty will cause an assertion failure in development.

Ember Data returns promise proxy objects when you read an async relationship and from other API. Ember proxy objects, including promise proxies, still require that you call get to read values.

My best guess is that the last item for a proxy describes what needs more detail in an error message.

1reaction
denzocommented, Apr 12, 2018
Read more comments on GitHub >

github_iconTop Results From Across the Web

Control flow and error handling - JavaScript - MDN Web Docs
Utilizing Error objects. Depending on the type of error, you may be able to use the name and message properties to get a...
Read more >
Documentation - Narrowing - TypeScript
JavaScript has an operator for determining if an object has a property with a name: the in operator. TypeScript takes this into account...
Read more >
5 Most Common useState Mistakes React Developers Often ...
Initializing useState Wrongly; Not Using Optional Chaining; Updating useState Directly; Updating Specific Object Property; Managing Multiple ...
Read more >
A Definitive Guide to Handling Errors in JavaScript - Kinsta
Errors in programming refer to situations that don't let a program function normally. It can happen when a program doesn't know how to...
Read more >
Safari Technology Preview Release Notes - Apple Developer
Release 156 · Web Inspector · CSS · JavaScript · Rendering · Media · Web Animations · Accessibility · Web API.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found