Loading...
Loading...
Use when writing, fixing, or editing TypeScript data models, DTOs, discriminated unions, classes, object boundaries, optional fields, null or undefined absence, repeated conditionals, impossible states, or object-chain access.
npx skill4agent add gosukiwi/clean-code-react clean-typescript-objects-data// Good - behavior belongs with the object
interface Employee {
calculatePay(): number;
}
class SalariedEmployee implements Employee {
constructor(private readonly salary: number) {}
calculatePay(): number {
return this.salary;
}
}// Bad - many invalid combinations are possible
type Employee = {
type: "SALARIED" | "HOURLY";
salary?: number;
hours?: number;
rate?: number;
};
// Good - each variant has exactly the fields it needs
type Employee =
| { type: "SALARIED"; salary: number }
| { type: "HOURLY"; hours: number; rate: number };nevertype Employee =
| { type: "SALARIED"; salary: number }
| { type: "HOURLY"; hours: number; rate: number }
| { type: "COMMISSIONED"; base: number; commission: number };
function calculatePay(employee: Employee): number {
switch (employee.type) {
case "SALARIED":
return employee.salary;
case "HOURLY":
return employee.hours * employee.rate;
case "COMMISSIONED":
return employee.base + employee.commission;
default:
return assertNever(employee);
}
}
function assertNever(value: never): never {
throw new Error(`Unhandled employee type: ${JSON.stringify(value)}`);
}// Bad - reaching through another object's internals
const outputDir = context.options.scratchDir.absolutePath;
// Good - ask the owner object
const outputDir = context.getScratchDir();nullundefinednull// Bad - caller cannot tell why there is no user
function findUser(id: string): User | null {
// ...
}
// Good - absence is the domain concept
function findUser(id: string): User | undefined {
// ...
}switch// Bad - the same status branching spreads through the codebase
if (invoice.status === "paid") {
// ...
}
// Good - one owner expresses the policy
if (canSendReceipt(invoice)) {
// ...
}null