There are two basic issues with the situation you have described—one of them related to TypeScript, one of them not.
The TypeScript issue is that TS is aware of the names of properties in general, and will check that you’re setting things correctly—both when using normal JS property lookup and assignment, and when using Ember’s get
and set
functions. Specifically, the types for Ember try to make sure you don’t end up typo-ing things when doing get
and set
. You can see why they don’t allow arbitrary strings in this example:
import Component from '@ember/component';
import { action, set } from '@ember/object';
export default class Whoops extends Component {
greeting = 'Hello';
@action updateGreeting(newGreeting) {
set(this, 'greering', newGreeting);
// ----^--- TYPO!!!
}
}
If the types for set
(or get
) just allowed arbitrary strings, TS couldn’t help you at all here; it would let it go, and you’d have to figure out the bug yourself—instead of the compiler helpfully telling you about it ahead of time.
In the case you’re running into, TypeScript presumably just sees a string, and it says “I don't have any way to check if this string belongs to the property.”
There are a couple ways to improve things here. First of all, if you can, you should figure out if it’s possible to constrain the type of propertyName
to be a keyof
for the type it’s coming from. (Explaining keyof
is beyond the scope of this answer, this section in the handbook and this blog post will get you up to speed.)
Second, though, and connected to the bigger issue: you noted in discussion to the other answer on this question that the problem is that you’re trying to deeply set properties on a single piece of tracked root state. In general, you should not mutate autotracked state this way—it’s a holdover from the old observers-driven patterns that Ember Classic used with its computed properties. Instead, prefer to drive all changes to that autotracked state through the owner of that state. Then you won’t need set
at all, and the system will update correctly automatically.
You can do that either by making the nested state itself be autotracked, either by defining a class for it or by using something like tracked-built-ins to wrap a plain JS object. Either way, instead of reaching in and deeply mutating that state from just anywhere, do it only on the object that owns that state. If you follow that pattern, and constrain the propertyName
to be a keyof TheOwnerOfTheState
where TheOwnerOfTheState
is some class, everything will “just work”—both on the Ember side and the TypeScript side.