Call-or-construct, like Boolean/Date: Task(recipe) and new Task(recipe) build the
same lazy Task. ES classes reject the call form, so the export is a Proxy whose apply
forwards to construction — statics, instanceof, and the prototype all pass through.
import { type Failure } from '../result/failure.ts'; type ChangeScan = { scope: 'paths'; paths: Set<string> }; type GitScanFailure = Failure<'GitScanFailed', { ref: string }>; const runGit = async (args: string[]): Promise<ChangeScan> => ({ scope: 'paths', paths: new Set(args) }); const scan = Task<ChangeScan, GitScanFailure>(() => runGit(['status'])); // no `new` scan instanceof Task && scan instanceof Promise; // true, true
The instance type of Task — value and type share the name, so a signature reads
Task<Config, ConfigFailure> while the same identifier constructs one.
const load = (id: number): Task<{ id: number }> => Task(() => ({ id })); await load(7); // { id: 7 }