ember-cli-typescript
ember-cli-typescript copied to clipboard
[ember-data] references API is not compatible with [email protected] and higher
The problem appears when you try to use this.belongsTo(
or this.hasMany(
in scope of a model method or accesor. In this case this
is broken, and it complains about the invalid invocation, until this
type is explicitly specified in the method signature.
Unfortunately, an explicit this
workaround doesn't work for accesors in [email protected] and higher, since they forbidden to specify this
on getters/setters, see https://github.com/microsoft/TypeScript/issues/39254#issuecomment-649831793.
Which package(s) does this problem pertain to?
- [ ] @types/ember
- [ ] @types/ember__string
- [ ] @types/ember__polyfills
- [ ] @types/ember__object
- [ ] @types/ember__utils
- [ ] @types/ember__array
- [ ] @types/ember__engine
- [ ] @types/ember__debug
- [ ] @types/ember__runloop
- [ ] @types/ember__error
- [ ] @types/ember__controller
- [ ] @types/ember__component
- [ ] @types/ember__routing
- [ ] @types/ember__application
- [ ] @types/ember__test
- [ ] @types/ember__test-helpers
- [ ] @types/ember__service
- [x] @types/ember-data
- [ ] @types/rsvp
- [ ] Other
- [ ] I don't know
What are instructions we can follow to reproduce the issue?
export default class User extends Model {
@belongsTo("user")
friend!: AsyncBelongsTo<User>;
// `this: User` leads to the following compilation error:
// > get' and 'set' accessors cannot declare 'this' parameters.t
get friendId(this: User) {
// if don't specify `this`, it'd fail on the next line
return this.belongsTo("friend").value()?.id;
}
}
Reproduction Case
Link: https://codesandbox.io/s/my-app-forked-zqghf?file=/app/models/user.ts
Now about that bug. What did you expect to see?
I expect:
export default class User extends Model {
@belongsTo("user")
friend!: AsyncBelongsTo<User>;
get friendId() {
return this.belongsTo("friend").value()?.id;
}
}
to work w/o a need for explicit this
and compilation errors.
What happened instead?
If remove an explicit this
from the signature,
return this.belongsTo("friend").value()?.id;
would lead to a compilation error:
Argument of type 'string' is not assignable to parameter of type 'Exclude<keyof this, "isEmpty" | "isLoading" | "isLoaded" | "hasDirtyAttributes" | "isSaving" | "isDeleted" | "isNew" | "isValid" | "dirtyType" | "isError" | "isReloading" | "id" | ... 41 more ... | "toString">'.ts(2345) Compilation error:
A while ago, I did a PR(https://github.com/DefinitelyTyped/DefinitelyTyped/pull/42839), which fixed the belongsTo(
, hasMany(
return types. And as a side effect, it did also fix this corrupted this
issue.
Unfortunately it has never been merged. Happy to reopen it.
@ro0gr thanks for writing this up and sorry that PR ended up languishing. If you reopen it, I’ll help you get it landed!
@chriskrycho thanks for the heads up! Glad to hear that.
Ok, I'll give it another try this weekend.
A workaround is to use call
and pass the reference as an argument, like such
return this.belongsTo.call(this, 'friend').value().id
// Or
return this.belongsTo.call(this, 'friend').id()
My workaround ended up being
get friendId() {
let inst = this as User;
return this.belongsTo("friend").value()?.id;
}
though I suspect I may be encountering a slightly separate issue