Last active
November 20, 2025 09:57
-
-
Save jnicklas/0a8d136d84ff9757819e0f20c34f625a to your computer and use it in GitHub Desktop.
Type safe setting of async associations in ember
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { set } from '@ember/object'; | |
| import type { AsyncBelongsTo, AsyncHasMany } from '@ember-data/model'; | |
| type ErrorMessage<T> = { __errorMessage: T }; | |
| export type AssociationSetterValueFrom<T> = | |
| T extends AsyncBelongsTo<infer U> | |
| ? AsyncBelongsTo<U> | U | null | |
| : T extends AsyncHasMany<infer U> | |
| ? U[] | |
| : ErrorMessage<'Must be an AsyncBelongsTo or AsyncHasMany association'>; | |
| // Sets an association on a model, accepting both the related model instance and | |
| // the AsyncBelongsTo/AsyncHasMany proxy. Ember Data does not currently support | |
| // setting associations with the proxied types, but this utility allows us to do | |
| // so in a type-safe manner. | |
| // | |
| // Example usage: | |
| // | |
| // import { setAsyncAssociation } from 'teamtailor/utils/set-association'; | |
| // | |
| // const job = this.store.createRecord('job'); | |
| // const pickedQuestion = this.store.createRecord('picked-question'); | |
| // | |
| // // Both usages are valid: | |
| // setAsyncAssociation(pickedQuestion, 'job', job); | |
| // setAsyncAssociation(pickedQuestion, 'job', pickedQuestion.job); // job is AsyncBelongsTo<JobModel> | |
| // setAsyncAssociation(pickedQuestion, 'job', pickedQuestion); // type error! | |
| export function setAsyncAssociation< | |
| M extends object, | |
| K extends keyof M & string, | |
| >(model: M, name: K, value: AssociationSetterValueFrom<M[K]>) { | |
| set(model, name, value); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment