thin-wrapper-functions
a function that only renames parameters or forwards to another
The argument
Anti-Patterns to Avoid
Thin Wrapper Functions
Don't create functions that only rename parameters or forward to another function:
// ❌ adds nothing but indirection
export const buildBrowserLabel = ({ browser, browserVersion }) =>
buildVersionedLabel({ name: browser, version: browserVersion });
// ✅ call the underlying function directly at the call site
A wrapper IS justified when it adds real validation/transformation, meaningfully simplifies a complex API, or handles errors/defaults.
Delegation to a held collaborator is not a thin wrapper
A class that holds a collaborator instead of extending one — the remedy the composition-over-inheritance rule requires — reaches it through one-line methods that forward unchanged. Those methods are the seam that rule asks for, not indirection to delete:
// ✅ the composition remedy: the sharing is visible at the seam
export class RefactorRun {
private readonly runState: RunState;
update({ patch }: { patch: Partial<RunManifest> }): Promise<void> {
return this.runState.update({ patch });
}
}
Deleting them means publishing the held value so callers can reach through it, and a caller that can reach through it can also step around a sibling method that adds something — a timer, a counter, a progress line — on the same call. The forward is what keeps the class's surface the only way in.
This carve-out covers a class delegating to something it holds, and nothing else. A free function that only forwards to another free function is still a thin wrapper.
The proof
import { buildVersionedLabel } from './buildVersionedLabel';
interface Params {
browser: string;
browserVersion: string;
}
// Adds nothing but indirection: no validation, no defaults, no error handling —
// only two parameters renamed on their way through.
export const buildBrowserLabel = ({ browser, browserVersion }: Params): string =>
buildVersionedLabel({ name: browser, version: browserVersion });
import { buildVersionedLabel } from '../common/utils/buildVersionedLabel';
interface Params {
browser: string;
browserVersion: string;
}
// The call site does the renaming, so there is no second function to keep in
// step with the first.
export const getBrowserBadge = ({ browser, browserVersion }: Params): string =>
`<span>${buildVersionedLabel({ name: browser, version: browserVersion })}</span>`;
Turn it down
Both lines go in your lightsout.config.json.
"standards-checks": { "thin-wrapper-functions": "advisory" }"standards-checks": { "thin-wrapper-functions": "off" }