From 9d1003028cfb1ca382b3ff87bafe8ec9c0235007 Mon Sep 17 00:00:00 2001 From: Svyatoslav Zaytsev Date: Sun, 23 Oct 2022 22:19:24 +0300 Subject: [PATCH] fix(eslint-plugin): isTypeReadonly stack overflow (#4476) --- .../prefer-readonly-parameter-types.test.ts | 18 ++++++++++++++++++ packages/type-utils/src/isTypeReadonly.ts | 4 ++++ .../type-utils/tests/isTypeReadonly.test.ts | 14 ++++++++++++++ 3 files changed, 36 insertions(+) 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 219b8cbdb08..b6b499b0efd 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 42dcc2ce907..cac7690ea3a 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 60d822b57a1..77d9f65b2f9 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', () => {