Loading...
Loading...
Use when writing, fixing, or editing TypeScript async flows, promises, retries, timeouts, cancellation, shared mutable state across awaits, race conditions, or flaky async tests.
npx skill4agent add gosukiwi/clean-code-react clean-typescript-asyncasync function importUsers(file: FileHandle, repository: UserRepository) {
const rows = await file.readRows();
const users = rows.map(parseUserRow);
await repository.saveMany(users);
}awaitPromise.all// Bad - promises are created but not awaited by forEach
users.forEach(async (user) => {
await sendInvite(user);
});
// Good - independent work is explicit
await Promise.all(users.map((user) => sendInvite(user)));await// Bad - concurrent calls can corrupt shared state
let cachedUser: User | undefined;
async function getUser(id: string) {
if (!cachedUser) {
cachedUser = await fetchUser(id);
}
return cachedUser;
}
// Good - cache key and mutation ownership are explicit
const userCache = new Map<string, Promise<User>>();
function getUser(id: string) {
const existing = userCache.get(id);
if (existing) {
return existing;
}
const request = fetchUser(id).catch((error: unknown) => {
userCache.delete(id);
throw error;
});
userCache.set(id, request);
return request;
}const USER_LOOKUP_TIMEOUT_MS = 2_000;
await fetchUser(userId, {
signal: AbortSignal.timeout(USER_LOOKUP_TIMEOUT_MS),
});test("deduplicates concurrent user fetches", async () => {
const fetchUser = vi.fn().mockResolvedValue({ id: "user-1" });
const users = createUserLoader(fetchUser);
await Promise.all([users.get("user-1"), users.get("user-1")]);
expect(fetchUser).toHaveBeenCalledTimes(1);
});