| paths | ||
|---|---|---|
|
Functions with >1 parameter use an object parameter with a {FunctionName}Input type.
type FormatCurrencyInput = { value: number; currency: string; decimals?: number }
const formatCurrency = ({ value, currency, decimals }: FormatCurrencyInput) => { ... }Exceptions: two obvious args with clear context (Math.max(a, b)), or required arg + optional config.
- NEVER use try-catch blocks for error handling
- ONLY use
attempt()for: showing errors to users, executing alternative logic, or providing fallback values - Let errors bubble up naturally — don't wrap functions just to log
// Good — show error to user
const result = await attempt(() => saveUserData(data))
if ('data' in result) showSuccessMessage()
else showErrorToUser(result.error.message)
// Good — fallback value
const config = attempt(() => parseConfig(raw))
const finalConfig = 'data' in config ? config.data : defaultConfig
// Bad — catching just to log
try {
await saveUserData(data)
} catch (e) {
console.error(e)
throw e
}Mappers, formatters, and transformers must be pure — no side effects, no mutations, no external state.
// Good — pure mapper
const mapApiTokenToToken = (apiToken: ApiToken): Token => ({
symbol: apiToken.symbol,
price: parseNumber(apiToken.price),
change24h: parseNumber(apiToken.change_24h),
})
// Bad — mutates input
const mapApiTokenToToken = (apiToken: ApiToken) => {
apiToken.price = parseFloat(apiToken.price) // mutation!
return apiToken as unknown as Token // cast!
}Use early returns to handle edge cases at the top, keeping the happy path unindented.
// Good — guards at top, happy path flat
const processOrder = (order: Order) => {
if (order.amount <= 0) return { error: 'Invalid amount' }
if (!order.tokenId) return { error: 'Missing token' }
const fee = calculateFee(order)
const total = order.amount + fee
return { data: { ...order, fee, total } }
}
// Bad — deeply nested
const processOrder = (order: Order) => {
if (order.amount > 0) {
if (order.tokenId) {
const fee = calculateFee(order)
// ... deep nesting continues
}
}
}- Actions: verb prefix —
createOrder,updatePosition,deleteToken - Getters:
getprefix —getTokenPrice,getFormattedBalance - Predicates:
is/has/shouldprefix, returns boolean —isActive,hasBalance,shouldRefetch - Mappers:
mapXxxToYyy—mapApiTokenToToken,mapOrderToUiOrder - Formatters:
formatprefix —formatCurrency,formatPercent - Validators:
validateprefix —validateOrder,validateAddress - Event handlers:
handleXxxinternally,onXxxfor props
Use arrow function expressions, not function declarations.
// Good
const calculateFee = (amount: number) => amount * 0.001
// Bad
function calculateFee(amount: number) {
return amount * 0.001
}Exception: exported functions that need hoisting (rare).
Each function does one thing. If a function name needs "and" to describe it, split it.
// Bad
const fetchAndFormatTokens = async () => { ... }
// Good
const fetchTokens = async () => { ... }
const formatTokens = (tokens: Token[]) => { ... }