@typescript-eslint/prefer-readonly-parameter-types
Require the types of function parameters to be read-only
Also called typescript-eslint/prefer-readonly-parameter-types, typescript/prefer-readonly-parameter-types
A function that sorts, pushes to, or assigns into its argument changes the caller's data. The caller can't see that from the call. If the parameter has a read-only type, TypeScript rejects those changes in the function body, and the signature promises the caller that the value comes back unchanged.
The check is deep, so a readonly array of objects that can be changed is still reported. Strings, numbers, and other primitives are always fine, and so are functions.
Configure#
Off by default. This rule needs types, so turning it on makes bun lint type check your code first.
[lint.rules]
"@typescript-eslint/prefer-readonly-parameter-types" = "error" # or "warn"Every option, set to its default:
[lint.rules]
"@typescript-eslint/prefer-readonly-parameter-types" = ["error", {
allow = [], # list of strings or objects
checkParameterProperties = true,
ignoreInferredTypes = false,
treatMethodsAsReadonly = false,
}]Examples#
function total(prices: number[]Parameter should be a read only type.) {}
function rename(user: { name: string }Parameter should be a read only type.) {}
function names(users: readonly { name: string }[]Parameter should be a read only type.) {}function total(prices: readonly number[]) {}
function rename(user: Readonly<{ name: string }>) {}
function names(users: readonly { readonly name: string }[]) {}
function repeat(text: string, times: number, done: () => void) {}Options#
| Option | Default | What it does |
|---|---|---|
allow | [] | Types that are accepted as they are. |
checkParameterProperties | true | Check constructor parameters that declare a field, such as private items: string[]. |
ignoreInferredTypes | false | Skip parameters that have no type annotation. |
treatMethodsAsReadonly | false | Accept methods that aren't marked readonly. |
Each allow entry is a type name, or an object that also says where the type comes from: { "from": "file", "name": "Draft" }, { "from": "lib", "name": "Date" }, or { "from": "package", "name": "Draft", "package": "some-package" }.
A Date is reported by default:
function format(date: DateParameter should be a read only type.) {}With allow: [{ "from": "lib", "name": "Date" }] it's accepted:
{ "allow": [{ "from": "lib", "name": "Date" }] }No problemsfunction format(date: Date) {}A callback's parameter often gets its type from the function you pass the callback to, which you might not control. Here row is a string[], so it's reported:
const rows = [["a", "b"], ["c"]];
rows.forEach(rowParameter should be a read only type. => console.log(row.length));With ignoreInferredTypes: true it's skipped:
{ "ignoreInferredTypes": true }No problemsconst rows = [["a", "b"], ["c"]];
rows.forEach(row => console.log(row.length));A method written as save(): void can be assigned to, so it counts as something that can change:
interface Store {
save(): void;
}
function flush(store: StoreParameter should be a read only type.) {}With treatMethodsAsReadonly: true it doesn't:
{ "treatMethodsAsReadonly": true }No problemsinterface Store {
save(): void;
}
function flush(store: Store) {}When not to use it#
This rule is strict. Most library and DOM types aren't read-only, and every function that takes one is reported until you list the type under allow.