Skip to main content

prefer-readonly-parameter-types

Require function parameters to be typed as readonly to prevent accidental mutation of inputs.

💭

该规则需要 类型信息 才能运行。


改变函数参数可能会导致令人困惑且难以调试的行为。 虽然很容易隐式记住不要修改函数参数,但显式将参数键入为只读可以为消费者提供明确的契约。 该合约使消费者更容易推断函数是否有副作用。

英:Mutating function arguments can lead to confusing, hard to debug behavior. Whilst it's easy to implicitly remember to not modify function arguments, explicitly typing arguments as readonly provides clear contract to consumers. This contract makes it easier for a consumer to reason about if a function has side-effects.

此规则允许你强制将函数参数解析为只读类型。 在以下情况下,类型被视为只读:

英:This rule allows you to enforce that function parameters resolve to readonly types. A type is considered readonly if:

  • 它是一个原始类型(stringnumberbooleansymbol 或枚举),
  • 它是一个函数签名类型,
  • 它是一个只读数组类型,其元素类型被视为只读。
  • 它是一个只读元组类型,其元素都被视为只读。
  • 它是一种对象类型,其属性全部标记为只读,并且其值全部被视为只读。
.eslintrc.cjs
module.exports = {
"rules": {
"@typescript-eslint/prefer-readonly-parameter-types": "error"
}
};
在线运行试试这个规则 ↗

示例

function array1(arg: string[]) {} // array is not readonly
function array2(arg: readonly string[][]) {} // array element is not readonly
function array3(arg: [string, number]) {} // tuple is not readonly
function array4(arg: readonly [string[], number]) {} // tuple element is not readonly
// the above examples work the same if you use ReadonlyArray<T> instead

function object1(arg: { prop: string }) {} // property is not readonly
function object2(arg: { readonly prop: string; prop2: string }) {} // not all properties are readonly
function object3(arg: { readonly prop: { prop2: string } }) {} // nested property is not readonly
// the above examples work the same if you use Readonly<T> instead

interface CustomArrayType extends ReadonlyArray<string> {
prop: string; // note: this property is mutable
}
function custom1(arg: CustomArrayType) {}

interface CustomFunction {
(): void;
prop: string; // note: this property is mutable
}
function custom2(arg: CustomFunction) {}

function union(arg: string[] | ReadonlyArray<number[]>) {} // not all types are readonly

// rule also checks function types
interface Foo {
(arg: string[]): void;
}
interface Foo {
new (arg: string[]): void;
}
const x = { foo(arg: string[]): void {} };
function foo(arg: string[]);
type Foo = (arg: string[]) => void;
interface Foo {
foo(arg: string[]): void;
}
Open in Playground

选项

allow

一些复杂类型不能轻易地变为只读,例如 HTMLElement 类型或 @types/jquery 中的 JQueryStatic 类型。 此选项允许你全局禁用此类类型的报告。

英:Some complex types cannot easily be made readonly, for example the HTMLElement type or the JQueryStatic type from @types/jquery. This option allows you to globally disable reporting of such types.

每个项目必须是以下之一:

英:Each item must be one of:

  • 文件中定义的类型({from: "file", name: "Foo", path: "src/foo-file.ts"}path 是相对于项目根目录的可选路径)
  • 默认库中的类型 ({from: "lib", name: "Foo"})
  • 来自包的类型({from: "package", name: "Foo", package: "foo-lib"},这也适用于在 typings 包中定义的类型)。

此外,类型可以定义为简单的字符串,然后该字符串与类型无关地匹配其来源。

英:Additionally, a type may be defined just as a simple string, which then matches the type independently of its origin.

此规则的代码示例:

英:Examples of code for this rule with:

{
"allow": [
"$",
{ "source": "file", "name": "Foo" },
{ "source": "lib", "name": "HTMLElement" },
{ "from": "package", "name": "Bar", "package": "bar-lib" }
]
}
interface ThisIsMutable {
prop: string;
}

interface Wrapper {
sub: ThisIsMutable;
}

interface WrapperWithOther {
readonly sub: Foo;
otherProp: string;
}

// Incorrect because ThisIsMutable is not readonly
function fn1(arg: ThisIsMutable) {}

// Incorrect because Wrapper.sub is not readonly
function fn2(arg: Wrapper) {}

// Incorrect because WrapperWithOther.otherProp is not readonly and not in the allowlist
function fn3(arg: WrapperWithOther) {}
Open in Playground
import { Foo } from 'some-lib';
import { Bar } from 'incorrect-lib';

interface HTMLElement {
prop: string;
}

// Incorrect because Foo is not a local type
function fn1(arg: Foo) {}

// Incorrect because HTMLElement is not from the default library
function fn2(arg: HTMLElement) {}

// Incorrect because Bar is not from "bar-lib"
function fn3(arg: Bar) {}
Open in Playground

checkParameterProperties

此选项允许你启用或禁用参数属性检查。 由于参数属性在类上创建属性,因此可能不希望强制它们为只读。

英:This option allows you to enable or disable the checking of parameter properties. Because parameter properties create properties on the class, it may be undesirable to force them to be readonly.

此规则与 {checkParameterProperties: true} 的代码示例:

英:Examples of code for this rule with {checkParameterProperties: true}:

class Foo {
constructor(private paramProp: string[]) {}
}
Open in Playground

此规则的 correct 代码与 {checkParameterProperties: false} 的示例:

英:Examples of correct code for this rule with {checkParameterProperties: false}:

class Foo {
constructor(
private paramProp1: string[],
private paramProp2: readonly string[],
) {}
}
Open in Playground

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.

此规则与 {ignoreInferredTypes: true} 的代码示例:

英:Examples of code for this rule with {ignoreInferredTypes: true}:

import { acceptsCallback, CallbackOptions } from 'external-dependency';

acceptsCallback((options: CallbackOptions) => {});
Open in Playground
外部依赖.d.ts
export interface CallbackOptions {
prop: string;
}
type Callback = (options: CallbackOptions) => void;
type AcceptsCallback = (callback: Callback) => void;

export const acceptsCallback: AcceptsCallback;
Open in Playground

treatMethodsAsReadonly

此选项允许你将所有可变方法视为只读方法。 当你从不重新分配方法时,这可能是理想的。

英:This option allows you to treat all mutable methods as though they were readonly. This may be desirable when you are never reassigning methods.

此规则与 {treatMethodsAsReadonly: false} 的代码示例:

英:Examples of code for this rule with {treatMethodsAsReadonly: false}:

type MyType = {
readonly prop: string;
method(): string; // note: this method is mutable
};
function foo(arg: MyType) {}
Open in Playground

此规则的 correct 代码与 {treatMethodsAsReadonly: true} 的示例:

英:Examples of correct code for this rule with {treatMethodsAsReadonly: true}:

type MyType = {
readonly prop: string;
method(): string; // note: this method is mutable
};
function foo(arg: MyType) {}
Open in Playground

何时不使用它

如果你的项目不尝试强制执行参数的强不可变性保证,则可以避免此规则。

英:If your project does not attempt to enforce strong immutability guarantees of parameters, you can avoid this rule.

选项

该规则接受以下选项

type Options = [
{
allow?: (
| {
from: 'file';
name: [string, ...string[]] | string;
path?: string;
}
| {
from: 'lib';
name: [string, ...string[]] | string;
}
| {
from: 'package';
name: [string, ...string[]] | string;
package: string;
}
| string
)[];
checkParameterProperties?: boolean;
ignoreInferredTypes?: boolean;
treatMethodsAsReadonly?: boolean;
},
];

const defaultOptions: Options = [
{
allow: [],
checkParameterProperties: true,
ignoreInferredTypes: false,
treatMethodsAsReadonly: false,
},
];

资源