Make properties and parameters required, and name them
Make object properties and function parameters required unless their absence has a meaning. When a function takes several parameters, especially booleans or values of the same type, take one options object so each value is named at the call site.
Implementation
- Mark a property or parameter optional only when leaving it out is a valid, meaningful case, such as an optional filter.
- When optional fields exist because an object represents several states, model the states as a discriminated union instead.
- When a function accumulates optional parameters for different use cases, split it into separate functions.
- Use a single options object when a function takes more than two or three parameters, or any boolean or same-typed parameters that are easy to swap.
- Keep simple positional parameters for one or two obviously distinct values, such as
isNumber(value)orclamp(value, min, max).
Rationale
Each optional field is a question every reader and caller must answer, and TypeScript cannot flag a caller that forgets a field that should have been required.
Positional parameters depend on order; transform('client', false, 60, 120, null, true, 2000) compiles even when two numbers are swapped, and the call site does not say what any value means.
Examples
Application: Positional parameters
Incorrect (counterexample):
transformUserInput('client', false, 60, 120, null, true, 2000);
Correct:
transformUserInput({
method: 'client',
isValidated: false,
minLines: 60,
maxLines: 120,
defaultInput: null,
shouldLog: true,
timeoutMs: 2000,
});
Application: Optional properties
Incorrect (counterexample):
type User = {
id?: number;
email?: string;
adminPermissions?: ReadonlyArray<string>;
temporaryToken?: string;
};
Every consumer must guess which combination of fields a given user has.
Correct:
type User =
| { role: 'admin'; id: number; email: string; adminPermissions: ReadonlyArray<string> }
| { role: 'guest'; temporaryToken: string };
Validation
Review each optional property or parameter and check that omitting it is a meaningful case. Review calls with several positional arguments and check that each value's meaning is obvious without reading the function.
An optional property whose absence is meaningful, or a short positional list of distinct values, is not a violation.