Loading...
Loading...
Use when writing, fixing, editing, or refactoring TypeScript functions with too many parameters, boolean flags, parameter mutation, deep nesting, mixed abstraction levels, complex conditionals, hidden side effects, dead helpers, unused exports, or unclear call sites.
npx skill4agent add gosukiwi/clean-code-react clean-typescript-functions// Bad - too many parameters
function createUser(
name: string,
email: string,
age: number,
country: string,
timezone: string,
language: string,
newsletter: boolean
) {
// ...
}
// Good - use a typed object
type UserData = {
name: string;
email: string;
age: number;
country: string;
timezone: string;
language: string;
newsletter: boolean;
};
function createUser(data: UserData) {
// ...
}type Report = {
content: string;
};
// Bad - modifies argument
function appendFooter(report: Report): void {
report.content += "\n---\nGenerated by System";
}
// Good - returns new value
function withFooter(report: Report): Report {
return {
...report,
content: `${report.content}\n---\nGenerated by System`,
};
}// Bad - function does two different things
function render(isTest: boolean) {
if (isTest) {
renderTestPage();
} else {
renderProductionPage();
}
}
// Good - split into two functions
function renderTestPage() {}
function renderProductionPage() {}ifforwhilemapforEachreduce// Bad - the useful path is buried
function getInvoiceTotal(invoice: Invoice): number {
if (invoice.status !== "void") {
if (invoice.items.length > 0) {
return invoice.items.reduce((total, item) => total + item.price, 0);
}
}
return 0;
}
// Good - guard clauses keep the normal path visible
function getInvoiceTotal(invoice: Invoice): number {
if (invoice.status === "void") {
return 0;
}
if (invoice.items.length === 0) {
return 0;
}
return invoice.items.reduce((total, item) => total + item.price, 0);
}// Bad - business rule, string parsing, and storage detail are interleaved
function activateUser(rawUser: string, storage: Storage) {
const [id, email] = rawUser.split(",");
if (!email.includes("@")) {
throw new Error("Invalid email");
}
storage.setItem(`user:${id}`, JSON.stringify({ id, email, active: true }));
}
// Good - this function reads at the policy level
function activateUser(rawUser: string, storage: UserStorage) {
const user = parseUser(rawUser);
assertCanActivate(user);
storage.save(activate(user));
}const isPrivilegedUser = user.role === "admin" || user.role === "owner";
// Bad - negated compound condition
if (!(isPrivilegedUser || user.hasBillingAccess)) {
return false;
}
// Good - De Morgan's law makes each rejected case visible
if (!isPrivilegedUser && !user.hasBillingAccess) {
return false;
}// Bad - hard to tell what rule is being checked
if (!(user.role === "admin" || user.role === "owner") || user.suspended || !account.active) {
return false;
}
// Good - the condition has a name
if (!canManageAccount(user, account)) {
return false;
}
function canManageAccount(user: User, account: Account): boolean {
const hasPrivilegedRole = user.role === "admin" || user.role === "owner";
return hasPrivilegedRole && !user.suspended && account.active;
}canManageAccountisEligibleForRetryisNotInvalid// Bad - a getter changes storage
function getSession(userId: string): Session {
return sessions.get(userId) ?? createSession(userId);
}
// Good - side effect is explicit
function getOrCreateSession(userId: string): Session {
return sessions.get(userId) ?? createSession(userId);
}// Bad - calculation secretly writes
function calculateInvoiceTotal(invoice: Invoice): Money {
auditLog.write("invoice-total-calculated");
return sumInvoiceLines(invoice.lines);
}
// Good - pure calculation, explicit effect
function calculateInvoiceTotal(invoice: Invoice): Money {
return sumInvoiceLines(invoice.lines);
}