Merge branch 'elliott/resources' of github.com:sveltejs/svelte into elliott/resources

elliott/resources
Elliott Johnson 1 week ago
commit cc74b6dfd5

@ -23,12 +23,12 @@ export function resource(fn) {
/**
* @template T
* @implements {Partial<Promise<Awaited<T>>>}
* @implements {Partial<Promise<T>>}
*/
class Resource {
#init = false;
/** @type {() => T} */
/** @type {() => T | Promise<T>} */
#fn;
/** @type {Source<boolean>} */
@ -40,42 +40,19 @@ class Resource {
/** @type {Source<boolean>} */
#ready = state(false);
/** @type {Source<Awaited<T> | undefined>} */
/** @type {Source<T | undefined>} */
#raw = state(undefined);
/** @type {Source<Promise<any>>} */
/** @type {Source<Promise<T>>} */
#promise;
/** @type {Derived<Awaited<T> | undefined>} */
#current = derived(() => {
if (!get(this.#ready)) return undefined;
return get(this.#raw);
});
/** {@type Source<any>} */
#error = state(undefined);
/** @type {Derived<Promise<Awaited<T>>['then']>} */
// @ts-expect-error - I feel this might actually be incorrect but I can't prove it yet.
// we are technically not returning a promise that resolves to the correct type... but it _is_ a promise that resolves at the correct time
/** @type {Derived<Promise<T>['then']>} */
#then = derived(() => {
const p = get(this.#promise);
return async (resolve, reject) => {
const result = /** @type {Promise<Awaited<T>>} */ (
(async () => {
await p;
await tick();
return get(this.#current);
})()
);
if (resolve || reject) {
return result.then(resolve, reject);
}
return result;
};
return (resolve, reject) => p.then(resolve, reject);
});
/**
@ -98,6 +75,7 @@ class Resource {
this.#init = true;
}
/** @type {ReturnType<typeof deferred<T>>} */
const { resolve, reject, promise } = deferred();
this.#latest.push(resolve);
@ -114,7 +92,7 @@ class Resource {
set(this.#raw, value);
set(this.#error, undefined);
resolve(undefined);
resolve(value);
})
.catch((e) => {
const idx = this.#latest.indexOf(resolve);
@ -143,12 +121,12 @@ class Resource {
get finally() {
get(this.#then);
return (/** @type {any} */ fn) => {
return get(this.#then)().finally(fn);
return get(this.#then)(fn, fn);
};
}
get current() {
return get(this.#current);
return get(this.#ready) ? get(this.#raw) : undefined;
}
get error() {
@ -179,14 +157,14 @@ class Resource {
};
/**
* @param {Awaited<T>} value
* @param {T} value
*/
set = (value) => {
set(this.#ready, true);
set(this.#loading, false);
set(this.#error, undefined);
set(this.#raw, value);
set(this.#promise, Promise.resolve());
set(this.#promise, Promise.resolve(value));
};
}

Loading…
Cancel
Save