From ba4a33847e8a9401b7e6ebb4f850418c096474d1 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Thu, 17 Sep 2026 13:44:42 +0100 Subject: [PATCH] fix(prefer-timer-args): check UpdateExpressions & TemplateLiterals An `UpdateExpression` is a mutation so we can't safely inline it. For example: ```ts setTimeout(() => fn(i++), 10); // not the same as setTimeout(fn, 10, i++); ``` A `TemplateLiteral` may contain expressions which mutate, so we also now check those: ```ts setTimeout(() => `foo ${fn()} bar`, 10); ``` --- src/rules/prefer-timer-args.test.ts | 10 ++++++++++ src/rules/prefer-timer-args.ts | 8 ++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/rules/prefer-timer-args.test.ts b/src/rules/prefer-timer-args.test.ts index dc5b8f1..632d5e9 100644 --- a/src/rules/prefer-timer-args.test.ts +++ b/src/rules/prefer-timer-args.test.ts @@ -51,6 +51,16 @@ ruleTester.run('prefer-timer-args', preferTimerArgs, { 'setTimeout(() => fn({key: getData()}), 100)', 'setTimeout(fn.bind(null, getData()), 100)', + // Unsafe transformations - arguments mutate state + 'setTimeout(() => fn(i++), 100)', + 'setTimeout(() => fn(--i), 100)', + 'setTimeout(() => fn(delete obj.key), 100)', + 'setTimeout(fn.bind(null, i++), 100)', + + // Unsafe transformations - template literals containing calls + 'setTimeout(() => fn(`${getData()}`), 100)', + 'setTimeout(() => fn(`${i++}`), 100)', + // window.setTimeout examples 'window.setTimeout(doSomething, 100)', 'window.setTimeout(() => { doSomething(a); }, 100)', diff --git a/src/rules/prefer-timer-args.ts b/src/rules/prefer-timer-args.ts index ffed63b..bdd0d0a 100644 --- a/src/rules/prefer-timer-args.ts +++ b/src/rules/prefer-timer-args.ts @@ -37,9 +37,11 @@ function isSafeArgument(arg: Expression | SpreadElement): boolean { switch (arg.type) { case 'Identifier': case 'Literal': - case 'TemplateLiteral': return true; + case 'TemplateLiteral': + return arg.expressions.every(isSafeArgument); + case 'MemberExpression': if ( arg.object.type === 'Super' || @@ -76,7 +78,9 @@ function isSafeArgument(arg: Expression | SpreadElement): boolean { }); case 'UnaryExpression': - case 'UpdateExpression': + if (arg.operator === 'delete') { + return false; + } return isSafeArgument(arg.argument); case 'BinaryExpression':