diff --git a/docs/rules/prefer-readonly-type.md b/docs/rules/prefer-readonly-type.md index 1043c89c2..c7db101a2 100644 --- a/docs/rules/prefer-readonly-type.md +++ b/docs/rules/prefer-readonly-type.md @@ -106,7 +106,7 @@ The default options: ```ts { allowLocalMutation: false, - allowMutableReturnType: false, + allowMutableReturnType: true, checkImplicit: false, ignoreClass: false, ignoreInterface: false, diff --git a/src/rules/prefer-readonly-type.ts b/src/rules/prefer-readonly-type.ts index 7c68f0356..60f91d3a9 100644 --- a/src/rules/prefer-readonly-type.ts +++ b/src/rules/prefer-readonly-type.ts @@ -75,7 +75,7 @@ const defaultOptions: Options = { ignoreInterface: false, ignoreCollections: false, allowLocalMutation: false, - allowMutableReturnType: false, + allowMutableReturnType: true, }; // The possible error messages. diff --git a/tests/rules/prefer-readonly-type/ts/invalid.ts b/tests/rules/prefer-readonly-type/ts/invalid.ts index 9277990eb..6a28365e2 100644 --- a/tests/rules/prefer-readonly-type/ts/invalid.ts +++ b/tests/rules/prefer-readonly-type/ts/invalid.ts @@ -125,18 +125,12 @@ const tests: ReadonlyArray = [ }`, optionsSet: [[]], output: dedent` - function foo(): ReadonlyArray { + function foo(): Array { interface Foo { readonly bar: ReadonlyArray } }`, errors: [ - { - messageId: "type", - type: "TSTypeReference", - line: 1, - column: 17, - }, { messageId: "type", type: "TSTypeReference", @@ -155,18 +149,12 @@ const tests: ReadonlyArray = [ }`, optionsSet: [[]], output: dedent` - const foo = (): ReadonlyArray => { + const foo = (): Array => { interface Foo { readonly bar: ReadonlyArray } }`, errors: [ - { - messageId: "type", - type: "TSTypeReference", - line: 1, - column: 17, - }, { messageId: "type", type: "TSTypeReference", @@ -175,38 +163,6 @@ const tests: ReadonlyArray = [ }, ], }, - // Should fail on shorthand syntax Array type as return type. - { - code: dedent` - function foo(): number[] { - }`, - optionsSet: [[]], - output: dedent` - function foo(): readonly number[] { - }`, - errors: [ - { - messageId: "array", - type: "TSArrayType", - line: 1, - column: 17, - }, - ], - }, - // Should fail on shorthand syntax Array type as return type. - { - code: `const foo = (): number[] => {}`, - optionsSet: [[]], - output: `const foo = (): readonly number[] => {}`, - errors: [ - { - messageId: "array", - type: "TSArrayType", - line: 1, - column: 17, - }, - ], - }, // Should fail inside function. { code: dedent` @@ -331,7 +287,7 @@ const tests: ReadonlyArray = [ readonly baz: ReadonlyArray } ): { - readonly bar: ReadonlyArray, + readonly bar: Array, readonly baz: ReadonlyArray } { let foo: { @@ -350,12 +306,6 @@ const tests: ReadonlyArray = [ line: 3, column: 19, }, - { - messageId: "type", - type: "TSTypeReference", - line: 7, - column: 17, - }, { messageId: "type", type: "TSTypeReference", @@ -651,17 +601,11 @@ const tests: ReadonlyArray = [ // Function Index Signatures. { code: dedent` - function foo(): { [source: string]: string } { - return undefined; - } function bar(param: { [source: string]: string }): void { return undefined; }`, optionsSet: [[]], output: dedent` - function foo(): { readonly [source: string]: string } { - return undefined; - } function bar(param: { readonly [source: string]: string }): void { return undefined; }`, @@ -670,12 +614,6 @@ const tests: ReadonlyArray = [ messageId: "property", type: "TSIndexSignature", line: 1, - column: 19, - }, - { - messageId: "property", - type: "TSIndexSignature", - line: 4, column: 23, }, ], @@ -902,6 +840,254 @@ const tests: ReadonlyArray = [ }, ], }, + // Don't allow mutable return type. + { + code: dedent` + function foo(...numbers: ReadonlyArray): Array {} + function bar(...numbers: readonly number[]): number[] {}`, + optionsSet: [[{ allowMutableReturnType: false }]], + output: dedent` + function foo(...numbers: ReadonlyArray): ReadonlyArray {} + function bar(...numbers: readonly number[]): readonly number[] {}`, + errors: [ + { + messageId: "type", + type: "TSTypeReference", + line: 1, + column: 50, + }, + { + messageId: "array", + type: "TSArrayType", + line: 2, + column: 46, + }, + ], + }, + // Don't allow mutable return type. + { + code: dedent` + const foo = function(...numbers: ReadonlyArray): Array {} + const bar = function(...numbers: readonly number[]): number[] {}`, + optionsSet: [[{ allowMutableReturnType: false }]], + output: dedent` + const foo = function(...numbers: ReadonlyArray): ReadonlyArray {} + const bar = function(...numbers: readonly number[]): readonly number[] {}`, + errors: [ + { + messageId: "type", + type: "TSTypeReference", + line: 1, + column: 58, + }, + { + messageId: "array", + type: "TSArrayType", + line: 2, + column: 54, + }, + ], + }, + // Don't allow mutable return type. + { + code: dedent` + const foo = (...numbers: ReadonlyArray): Array => {} + const bar = (...numbers: readonly number[]): number[] => {}`, + optionsSet: [[{ allowMutableReturnType: false }]], + output: dedent` + const foo = (...numbers: ReadonlyArray): ReadonlyArray => {} + const bar = (...numbers: readonly number[]): readonly number[] => {}`, + errors: [ + { + messageId: "type", + type: "TSTypeReference", + line: 1, + column: 50, + }, + { + messageId: "array", + type: "TSArrayType", + line: 2, + column: 46, + }, + ], + }, + // Don't allow mutable return type. + { + code: dedent` + class Foo { + foo(...numbers: ReadonlyArray): Array { + } + } + class Bar { + foo(...numbers: readonly number[]): number[] { + } + }`, + optionsSet: [[{ allowMutableReturnType: false }]], + output: dedent` + class Foo { + foo(...numbers: ReadonlyArray): ReadonlyArray { + } + } + class Bar { + foo(...numbers: readonly number[]): readonly number[] { + } + }`, + errors: [ + { + messageId: "type", + type: "TSTypeReference", + line: 2, + column: 43, + }, + { + messageId: "array", + type: "TSArrayType", + line: 6, + column: 39, + }, + ], + }, + // Don't allow mutable return type with Type Arguments. + { + code: dedent` + function foo(...numbers: ReadonlyArray): Promise> {} + function foo(...numbers: ReadonlyArray): Promise {}`, + optionsSet: [[{ allowMutableReturnType: false }]], + output: dedent` + function foo(...numbers: ReadonlyArray): Promise> {} + function foo(...numbers: ReadonlyArray): Promise {}`, + errors: [ + { + messageId: "type", + type: "TSTypeReference", + line: 1, + column: 58, + }, + { + messageId: "array", + type: "TSArrayType", + line: 2, + column: 58, + }, + ], + }, + // Don't allow mutable return type with deep Type Arguments. + { + code: dedent` + type Foo = { readonly x: T; }; + function foo(...numbers: ReadonlyArray): Promise>> {} + function foo(...numbers: ReadonlyArray): Promise> {}`, + optionsSet: [[{ allowMutableReturnType: false }]], + output: dedent` + type Foo = { readonly x: T; }; + function foo(...numbers: ReadonlyArray): Promise>> {} + function foo(...numbers: ReadonlyArray): Promise> {}`, + errors: [ + { + messageId: "type", + type: "TSTypeReference", + line: 2, + column: 62, + }, + { + messageId: "array", + type: "TSArrayType", + line: 3, + column: 62, + }, + ], + }, + // Don't allow mutable return type with Type Arguments in a tuple. + { + code: dedent` + function foo(...numbers: ReadonlyArray): readonly [number, Array, number] {} + function foo(...numbers: ReadonlyArray): readonly [number, number[], number] {}`, + optionsSet: [[{ allowMutableReturnType: false }]], + output: dedent` + function foo(...numbers: ReadonlyArray): readonly [number, ReadonlyArray, number] {} + function foo(...numbers: ReadonlyArray): readonly [number, readonly number[], number] {}`, + errors: [ + { + messageId: "type", + type: "TSTypeReference", + line: 1, + column: 68, + }, + { + messageId: "array", + type: "TSArrayType", + line: 2, + column: 68, + }, + ], + }, + // Don't allow mutable return type with Type Arguments Union. + { + code: dedent` + function foo(...numbers: ReadonlyArray): { readonly a: Array } | { readonly b: string[] } {}`, + optionsSet: [[{ allowMutableReturnType: false }]], + output: dedent` + function foo(...numbers: ReadonlyArray): { readonly a: ReadonlyArray } | { readonly b: readonly string[] } {}`, + errors: [ + { + messageId: "type", + type: "TSTypeReference", + line: 1, + column: 64, + }, + { + messageId: "array", + type: "TSArrayType", + line: 1, + column: 96, + }, + ], + }, + // Don't allow mutable return type with Type Arguments Intersection. + { + code: dedent` + function foo(...numbers: ReadonlyArray): { readonly a: Array } & { readonly b: string[] } {}`, + optionsSet: [[{ allowMutableReturnType: false }]], + output: dedent` + function foo(...numbers: ReadonlyArray): { readonly a: ReadonlyArray } & { readonly b: readonly string[] } {}`, + errors: [ + { + messageId: "type", + type: "TSTypeReference", + line: 1, + column: 64, + }, + { + messageId: "array", + type: "TSArrayType", + line: 1, + column: 96, + }, + ], + }, + // Don't allow mutable return type with Type Arguments Conditional. + { + code: dedent` + function foo(x: T): T extends Array ? string : number[] {}`, + optionsSet: [[{ allowMutableReturnType: false }]], + output: dedent` + function foo(x: T): T extends ReadonlyArray ? string : readonly number[] {}`, + errors: [ + { + messageId: "type", + type: "TSTypeReference", + line: 1, + column: 34, + }, + { + messageId: "array", + type: "TSArrayType", + line: 1, + column: 59, + }, + ], + }, ]; export default tests; diff --git a/tests/rules/prefer-readonly-type/ts/valid.ts b/tests/rules/prefer-readonly-type/ts/valid.ts index fdc4e250f..4bee1a203 100644 --- a/tests/rules/prefer-readonly-type/ts/valid.ts +++ b/tests/rules/prefer-readonly-type/ts/valid.ts @@ -56,28 +56,28 @@ const tests: ReadonlyArray = [ code: `const foo: ReadonlyArray = [];`, optionsSet: [[]], }, - // Allow return type. + // Allow mutable return type. { code: dedent` function foo(...numbers: ReadonlyArray): Array {} function bar(...numbers: readonly number[]): number[] {}`, - optionsSet: [[{ allowMutableReturnType: true }]], + optionsSet: [], }, - // Allow return type. + // Allow mutable return type. { code: dedent` const foo = function(...numbers: ReadonlyArray): Array {} const bar = function(...numbers: readonly number[]): number[] {}`, - optionsSet: [[{ allowMutableReturnType: true }]], + optionsSet: [], }, - // Allow return type. + // Allow mutable return type. { code: dedent` const foo = (...numbers: ReadonlyArray): Array => {} const bar = (...numbers: readonly number[]): number[] => {}`, - optionsSet: [[{ allowMutableReturnType: true }]], + optionsSet: [], }, - // Allow return type. + // Allow mutable return type. { code: dedent` class Foo { @@ -88,47 +88,47 @@ const tests: ReadonlyArray = [ foo(...numbers: readonly number[]): number[] { } }`, - optionsSet: [[{ allowMutableReturnType: true }]], + optionsSet: [], }, - // Allow return type with Type Arguments. + // Allow mutable return type with Type Arguments. { code: dedent` function foo(...numbers: ReadonlyArray): Promise> {} function foo(...numbers: ReadonlyArray): Promise {}`, - optionsSet: [[{ allowMutableReturnType: true }]], + optionsSet: [], }, - // Allow return type with deep Type Arguments. + // Allow mutable return type with deep Type Arguments. { code: dedent` type Foo = { readonly x: T; }; function foo(...numbers: ReadonlyArray): Promise>> {} function foo(...numbers: ReadonlyArray): Promise> {}`, - optionsSet: [[{ allowMutableReturnType: true }]], + optionsSet: [], }, - // Allow return type with Type Arguments in a tuple. + // Allow mutable return type with Type Arguments in a tuple. { code: dedent` function foo(...numbers: ReadonlyArray): readonly [number, Array, number] {} function foo(...numbers: ReadonlyArray): readonly [number, number[], number] {}`, - optionsSet: [[{ allowMutableReturnType: true }]], + optionsSet: [], }, - // Allow return type with Type Arguments Union. + // Allow mutable return type with Type Arguments Union. { code: dedent` function foo(...numbers: ReadonlyArray): { readonly a: Array } | { readonly b: string[] } {}`, - optionsSet: [[{ allowMutableReturnType: true }]], + optionsSet: [], }, - // Allow return type with Type Arguments Intersection. + // Allow mutable return type with Type Arguments Intersection. { code: dedent` function foo(...numbers: ReadonlyArray): { readonly a: Array } & { readonly b: string[] } {}`, - optionsSet: [[{ allowMutableReturnType: true }]], + optionsSet: [], }, - // Allow return type with Type Arguments Conditional. + // Allow mutable return type with Type Arguments Conditional. { code: dedent` function foo(x: T): T extends Array ? string : number[] {}`, - optionsSet: [[{ allowMutableReturnType: true }]], + optionsSet: [], }, // Allow inline mutable return type. {