@@ -5,6 +5,8 @@ import { assert } from '@ember/debug';
5
5
// @ts -ignore
6
6
import { invokeHelper } from '@ember/helper' ;
7
7
8
+ import { INTERNAL } from 'core/function-based/types' ;
9
+
8
10
import { DEFAULT_THUNK , normalizeThunk } from '../utils' ;
9
11
10
12
import type { Cache , Thunk } from '../types' ;
@@ -169,10 +171,89 @@ export class Resource<T = unknown> {
169
171
*/
170
172
static from < T extends new ( ...args : any ) => any > (
171
173
this : T ,
172
- context : object ,
174
+ context : InstanceType < new ( ... args : any ) => any > ,
173
175
thunk ?: Thunk | ( ( ) => unknown )
176
+ ) : InstanceType < T > ;
177
+
178
+ /**
179
+ * For use in the body of a class.
180
+ *
181
+ * `from` is what allows resources to be used in JS, they hide the reactivity APIs
182
+ * from the consumer so that the surface API is smaller.
183
+ *
184
+ * ```js
185
+ * import { Resource, use } from 'ember-resources';
186
+ *
187
+ * class SomeResource extends Resource {}
188
+ *
189
+ * class MyClass {
190
+ * @use data = SomeResource.from(() => [ ... ]);
191
+ * }
192
+ * ```
193
+ */
194
+ static from < T extends new ( ...args : any ) => any > (
195
+ this : T ,
196
+ thunk : Thunk | ( ( ) => unknown )
197
+ ) : InstanceType < T > ;
198
+
199
+ static from < T extends new ( ...args : any ) => any > (
200
+ this : T ,
201
+ contextOrThunk : InstanceType < new ( ...args : any ) => any > | Thunk | ( ( ) => unknown ) ,
202
+ thunkOrUndefined ?: undefined | Thunk | ( ( ) => unknown )
174
203
) : InstanceType < T > {
175
- return resourceOf ( context , this , thunk ) ;
204
+ /**
205
+ * This first branch is for
206
+ *
207
+ * ```js
208
+ * class Foo {
209
+ * @use foo = SomeResource.from(() => [ ... ])
210
+ * }
211
+ * ```
212
+ *
213
+ * and in order to support this, we need to defer the passed
214
+ * thunk until when the decorator is accessed.
215
+ *
216
+ * The decorator mostly does what `resourceOf` is doing below, but
217
+ * a little more simply, because we don't have to deal with a Proxy.
218
+ *
219
+ */
220
+ if ( typeof contextOrThunk === 'function' ) {
221
+ /**
222
+ * This cast is a little weird, because the narrowing from the
223
+ * typeof check, while removing `object` from `contextOrThunk` does
224
+ * add in `Function` to the type union and I don't know of a better way
225
+ * to manage the type narrowing here.
226
+ */
227
+ let thunk = contextOrThunk as Thunk | ( ( ) => unknown ) ;
228
+
229
+ /**
230
+ * We have to lie here because TypeScript doesn't allow decorators
231
+ * to alter the type of a property.
232
+ *
233
+ * This is private API that the `@use` decorator understands,
234
+ * but is not supported for use by any other conusmer.
235
+ */
236
+ return {
237
+ thunk,
238
+ definition : this ,
239
+ type : 'class-based' ,
240
+ [ INTERNAL ] : true ,
241
+ } as unknown as InstanceType < T > ;
242
+ }
243
+
244
+ /**
245
+ * This usage is for decorator-less usage
246
+ *
247
+ * ```js
248
+ * class Foo {
249
+ * foo = SomeResource.from(this, () => [ ... ])
250
+ * }
251
+ * ```
252
+ *
253
+ * The only tradeoff is that a `this` needs to be passed.
254
+ *
255
+ */
256
+ return resourceOf ( contextOrThunk , this , thunkOrUndefined ) ;
176
257
}
177
258
178
259
// owner must be | unknown as to not
0 commit comments