// RecursivePartial definition based on https://stackoverflow.com/a/51365037 type RecursivePartial = { [P in keyof T]?: T[P] extends Array ? Array> : T[P] extends object ? RecursivePartial : T[P]; }; export function stub(base: RecursivePartial = {}): T { const store = new Map(); return new Proxy(base, { get(target, prop) { if (prop in target) return (target as any)[prop]; if (prop === 'then') return undefined; if (!store.has(prop)) store.set(prop, jest.fn()); return store.get(prop); }, has(target, prop) { if (prop in target) return true; if (prop === 'then') return false; return true; }, }) as T; } type Fn = (...args: any[]) => any; type ArgumentTypes = F extends (...args: infer A) => any ? A : never; type StubValue = T extends Fn ? jest.Mock, ArgumentTypes> : T; export type Stub = { [P in keyof T]: StubValue; }; export function reveal(original: T): Stub { return original as Stub; }