Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better TS types #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 25 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ enum Status {

interface CacheNode {
s: Status;
v: any; // value
v: unknown; // value
e: number; // expire
swr: number; // stale-while-revalidate
sie: number; // stale-if-error
Expand Down Expand Up @@ -43,43 +43,43 @@ function createCacheNode(
};
}

interface Options {
export interface Options<V> {
maxAge?: number;
swr?: number;
sie?: number;
maxCacheSize?: number;

cacheFulfilled?: (args: any[], value: any) => boolean;
cacheRejected?: (args: any[], error: any) => boolean;
cacheFulfilled?: (args: any[], value: unknown) => boolean;
cacheRejected?: (args: any[], error: unknown) => boolean;
argsEqual?: (a: any[], b: any[]) => boolean;
storeCreator?: (promiseFn: PromiseFn) => any;
storeCreator?: (promiseFn: PromiseFn<V>) => Store;
onEmitted?: (
event: string,
info: { cache: Store<any, CacheNode>; args?: any[]; gcCount?: number }
info: { cache: Store; args?: unknown[]; gcCount?: number }
) => void;
}

type PromiseFn = (...args: any[]) => Promise<any>;
export type PromiseFn<V> = (...args: any[]) => Promise<V>;

function createCacheStore(): Store<any, CacheNode> {
return new Store<any, CacheNode>();
function createCacheStore<V>(): Store {
return new Store();
}

/**
* @param {Function} promiseFn
* @param {Number} options.maxAge Cache validity period (ms), default is 0, when it is Infinity, it is cached permanently
* @param {Number} options.swr Cache expiration tolerance time (ms), default Infinity
* @param {Number} options.sie Update error tolerance time (ms), default is Infinity
* @param {maxCacheSize} options.maxCacheSize Maximum cache size
* @param {Number} options.maxCacheSize Maximum cache size
*
* @param {Function} options.cacheFulfilled Whether to cache the current normal result, the default is true (arguments, value) => boolean
* @param {Function} options.cacheRejected Whether to cache the current exception result, the default is false (arguments, error) => boolean
* @returns
*/
export default function swrPromise(
promiseFn: PromiseFn,
options: Options = {}
) {
export default function swrPromise<V>(
promiseFn: PromiseFn<V>,
options: Options<V> = {}
): PromiseFn<V> {
const {
maxAge = 0,
swr = Infinity,
Expand All @@ -92,8 +92,9 @@ export default function swrPromise(
onEmitted = () => {},
} = options;

const cacheStore = storeCreator(promiseFn) as Store<any, CacheNode>;
const cacheStore = storeCreator(promiseFn);

// @ts-expect-error corcurPromise type does use `unknown` type, but the returned promise has the same type as the input promise
promiseFn = concurPromise(promiseFn);

const callGC = throttle(() => {
Expand Down Expand Up @@ -136,6 +137,7 @@ export default function swrPromise(
onEmitted("gc", { cache: cacheStore, gcCount });
}, 5000);

// @ts-expect-error corcurPromise type does use `unknown` type, but the returned promise has the same type as the input promise
return concurPromise(function (...args: any[]) {
queueMacroTasks(callGC);

Expand Down Expand Up @@ -177,7 +179,7 @@ export default function swrPromise(
async function update(selfArgs: any[]) {
return promiseFn
.apply(null, selfArgs)
.then((value: any) => {
.then((value) => {
result.s = Status.TERMINATED;
result.v = value;
result.e = Date.now() + result._maxAge;
Expand Down Expand Up @@ -240,3 +242,10 @@ export default function swrPromise(
}
});
}

export type {
Store as SwrPromiseStore,
PromiseFn as SwrPromiseFunction,
Options as SwrPromiseOptions,
CacheNode as SwrPromiseCacheNode,
};
16 changes: 14 additions & 2 deletions src/store.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import type { SwrPromiseCacheNode as CacheNode } from "./index";

type Storage<A, T> = Map<A, T>;

const Storage = Map;

// A: Agreement, T: CacheNode
export default class Store<A, T> {
interface Store< A extends any[] = any[], T extends CacheNode = CacheNode> {
set(key: A, value: T): void;
get(key: A): T | undefined;
entries(): IterableIterator<[A, T]>;
delete(key: A): boolean;
size(): number;
}

// V: Value of data, A: Agreement, T: CacheNode
class Store< A extends any[], T extends CacheNode> {
store: Storage<A, T>;
constructor() {
this.store = new Storage<A, T>();
Expand Down Expand Up @@ -36,3 +46,5 @@ export default class Store<A, T> {
return this.store.size;
}
}

export default Store