From cb77b0e45783baf8803190a5f760ca93edb62d15 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Thu, 6 Feb 2020 21:01:08 -0800 Subject: [PATCH] docs: docs --- .../rules/prefer-readonly-parameter-types.md | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md diff --git a/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md b/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md new file mode 100644 index 000000000000..5b9500539a9c --- /dev/null +++ b/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md @@ -0,0 +1,91 @@ +# Requires that function parameters are typed as readonly to prevent accidental mutation of inputs (`prefer-readonly-parameter-types`) + +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. + +## Rule Details + +This rule allows you to enforce that function parameters resolve to readonly types. +A type is considered readonly if: + +- it is a primitive type (`string`, `number`, `boolean`, `symbol`, or an enum), +- it is a function signature type, +- it is a readonly array type whose element type is considered readonly. +- it is a readonly tuple type whose elements are all considered readonly. +- it is an object type whose properties are all marked as readonly, and whose values are all considered readonly. + +Examples of **incorrect** code for this rule: + +```ts +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 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 instead + +interface CustomArrayType extends ReadonlyArray { + 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) {} // not all types are readonly +``` + +Examples of **correct** code for this rule: + +```ts +function array1(arg: readonly string[]) {} +function array2(arg: readonly (readonly string[])[]) {} +function array3(arg: readonly [string, number]) {} +function array4(arg: readonly [readonly string[], number]) {} +// the above examples work the same if you use ReadonlyArray instead + +function object1(arg: { readonly prop: string }) {} +function object2(arg: { readonly prop: string; readonly prop2: string }) {} +function object3(arg: { readonly prop: { readonly prop2: string } }) {} +// the above examples work the same if you use Readonly instead + +interface CustomArrayType extends ReadonlyArray { + readonly prop: string; +} +function custom1(arg: CustomArrayType) {} + +interface CustomFunction { + (): void; + readonly prop: string; +} +function custom2(arg: CustomFunction) {} + +function union(arg: readonly string[] | ReadonlyArray) {} + +function primitive1(arg: string) {} +function primitive2(arg: number) {} +function primitive3(arg: boolean) {} +function primitive4(arg: unknown) {} +function primitive5(arg: null) {} +function primitive6(arg: undefined) {} +function primitive7(arg: any) {} +function primitive8(arg: never) {} +function primitive9(arg: string | number | undefined) {} + +function fnSig(arg: () => void) {} + +enum Foo { a, b } +function enum(arg: Foo) {} + +function symb1(arg: symbol) {} +const customSymbol = Symbol('a'); +function symb2(arg: typeof customSymbol) {} +```