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 219b8cbdb086..b6b499b0efda 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 @@ -5,6 +5,7 @@ import type { InferMessageIdsTypeFromRule, InferOptionsTypeFromRule, } from '../../src/util'; +import { readonlynessOptionsDefaults } from '../../src/util'; import { getFixturesRootDir, noFormat, RuleTester } from '../RuleTester'; type MessageIds = InferMessageIdsTypeFromRule; @@ -362,6 +363,23 @@ ruleTester.run('prefer-readonly-parameter-types', rule, { }, ], }, + { + name: 'circular readonly types (Bug: #4476)', + code: ` + interface Obj { + readonly [K: string]: Obj; + } + + function foo(event: Obj): void {} + `, + options: [ + { + checkParameterProperties: true, + ignoreInferredTypes: false, + ...readonlynessOptionsDefaults, + }, + ], + }, ], invalid: [ // arrays diff --git a/packages/type-utils/src/isTypeReadonly.ts b/packages/type-utils/src/isTypeReadonly.ts index 42dcc2ce9079..cac7690ea3a3 100644 --- a/packages/type-utils/src/isTypeReadonly.ts +++ b/packages/type-utils/src/isTypeReadonly.ts @@ -113,6 +113,10 @@ function isTypeReadonlyObject( return Readonlyness.Mutable; } + if (indexInfo.type === type) { + return Readonlyness.Readonly; + } + return isTypeReadonlyRecurser( checker, indexInfo.type, diff --git a/packages/type-utils/tests/isTypeReadonly.test.ts b/packages/type-utils/tests/isTypeReadonly.test.ts index 60d822b57a18..77d9f65b2f9f 100644 --- a/packages/type-utils/tests/isTypeReadonly.test.ts +++ b/packages/type-utils/tests/isTypeReadonly.test.ts @@ -134,6 +134,13 @@ describe('isTypeReadonly', () => { ); }); + describe('is readonly circular', () => { + const runTests = runTestIsReadonly; + + it('handles circular readonly PropertySignature inside a readonly IndexSignature', () => + runTests('interface Test { readonly [key: string]: Test };')); + }); + describe('is not readonly', () => { const runTests = runTestIsNotReadonly; @@ -145,6 +152,13 @@ describe('isTypeReadonly', () => { runTests, ); }); + + describe('is not readonly circular', () => { + const runTests = runTestIsNotReadonly; + + it('handles circular mutable PropertySignature inside a readonly IndexSignature', () => + runTests('interface Test { [key: string]: Test };')); + }); }); describe('Union', () => { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy