diff --git a/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md b/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md
index 74697f2d3e6..34544456f09 100644
--- a/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md
+++ b/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md
@@ -124,10 +124,12 @@ interface Foo {
```ts
interface Options {
checkParameterProperties?: boolean;
+ ignoreInferredTypes?: boolean;
}
const defaultOptions: Options = {
checkParameterProperties: true,
+ ignoreInferredTypes: false,
};
```
@@ -162,3 +164,53 @@ class Foo {
) {}
}
```
+
+### `ignoreInferredTypes`
+
+This option allows you to ignore parameters which don't explicitly specify a type. This may be desirable in cases where an external dependency specifies a callback with mutable parameters, and manually annotating the callback's parameters is undesirable.
+
+Examples of **incorrect** code for this rule with `{ignoreInferredTypes: true}`:
+
+```ts
+import { acceptsCallback, CallbackOptions } from 'external-dependency';
+
+acceceptsCallback((options: CallbackOptions) => {});
+```
+
+
+external-dependency.d.ts
+
+```ts
+export interface CallbackOptions {
+ prop: string;
+}
+type Callback = (options: CallbackOptions) => void;
+type AcceptsCallback = (callback: Callback) => void;
+
+export const acceptsCallback: AcceptsCallback;
+```
+
+
+
+Examples of **correct** code for this rule with `{ignoreInferredTypes: true}`:
+
+```ts
+import { acceptsCallback } from 'external-dependency';
+
+acceceptsCallback(options => {});
+```
+
+
+external-dependency.d.ts
+
+```ts
+export interface CallbackOptions {
+ prop: string;
+}
+type Callback = (options: CallbackOptions) => void;
+type AcceptsCallback = (callback: Callback) => void;
+
+export const acceptsCallback: AcceptsCallback;
+```
+
+
diff --git a/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts b/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts
index fdad0220c39..a36020e93d3 100644
--- a/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts
+++ b/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts
@@ -7,6 +7,7 @@ import * as util from '../util';
type Options = [
{
checkParameterProperties?: boolean;
+ ignoreInferredTypes?: boolean;
},
];
type MessageIds = 'shouldBeReadonly';
@@ -30,6 +31,9 @@ export default util.createRule({
checkParameterProperties: {
type: 'boolean',
},
+ ignoreInferredTypes: {
+ type: 'boolean',
+ },
},
},
],
@@ -40,9 +44,11 @@ export default util.createRule({
defaultOptions: [
{
checkParameterProperties: true,
+ ignoreInferredTypes: false,
},
],
- create(context, [{ checkParameterProperties }]) {
+ create(context, options) {
+ const [{ checkParameterProperties, ignoreInferredTypes }] = options;
const { esTreeNodeToTSNodeMap, program } = util.getParserServices(context);
const checker = program.getTypeChecker();
@@ -81,6 +87,11 @@ export default util.createRule({
param.type === AST_NODE_TYPES.TSParameterProperty
? param.parameter
: param;
+
+ if (ignoreInferredTypes && actualParam.typeAnnotation == null) {
+ continue;
+ }
+
const tsNode = esTreeNodeToTSNodeMap.get(actualParam);
const type = checker.getTypeAtLocation(tsNode);
const isReadOnly = util.isTypeReadonly(checker, type);
diff --git a/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts b/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts
index d5408a5d859..9278420a764 100644
--- a/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts
+++ b/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts
@@ -247,6 +247,24 @@ ruleTester.run('prefer-readonly-parameter-types', rule, {
const willNotCrash = (foo: Readonly) => {};
`,
+ {
+ code: `
+ type Callback = (options: T) => void;
+
+ declare const acceptsCallback: (callback: Callback) => void;
+
+ interface CallbackOptions {
+ prop: string;
+ }
+
+ acceptsCallback(options => {});
+ `,
+ options: [
+ {
+ ignoreInferredTypes: true,
+ },
+ ],
+ },
],
invalid: [
// arrays
@@ -671,5 +689,31 @@ ruleTester.run('prefer-readonly-parameter-types', rule, {
},
],
},
+ {
+ code: `
+ type Callback = (options: T) => void;
+
+ declare const acceptsCallback: (callback: Callback) => void;
+
+ interface CallbackOptions {
+ prop: string;
+ }
+
+ acceptsCallback((options: CallbackOptions) => {});
+ `,
+ options: [
+ {
+ ignoreInferredTypes: true,
+ },
+ ],
+ errors: [
+ {
+ messageId: 'shouldBeReadonly',
+ line: 10,
+ column: 43,
+ endColumn: 67,
+ },
+ ],
+ },
],
});