eslint-plugin-total-functions icon indicating copy to clipboard operation
eslint-plugin-total-functions copied to clipboard

[no-unsafe-readonly-mutable-assignment] False negative with Object.assign

Open boris-petrov opened this issue 3 years ago • 1 comments

const x: { readonly a: number } = { a: 1 };
Object.assign(x, { a: 3 });

This should warn, I guess, but it doesn't. Am I missing something? Shouldn't this rule handle that case?

boris-petrov avatar Dec 07 '20 13:12 boris-petrov

Thanks @boris-petrov, you're right. I'd be happy to accept a PR for this.

danielnixon avatar Dec 08 '20 00:12 danielnixon

I can recommend https://github.com/eslint-functional/eslint-plugin-functional/blob/main/docs/rules/immutable-data.md and even https://github.com/eslint-functional/eslint-plugin-functional/blob/main/docs/rules/no-expression-statements.md

Either of those rules will flag Object.assign(x, { a: 3 }); as problematic.

danielnixon avatar Mar 10 '23 09:03 danielnixon

It's difficult for this rule to catch this issue due to the way Object.assign is typed:

assign<T extends {}, U>(target: T, source: U): T & U

The parameter type declared by assign is T extends {} (in your case this is { readonly a: number }) and the argument type is the same.

So this rule is comparing assignment from T to T, which it considers valid.

This is distinct from the situation where you have an assignment like

        type ReadonlyA = { readonly a: string };
        const readonlyA: ReadonlyA = { a: "" };

where the types are different - { readonly a: string } and { a: string }.

For this reason I'm going to close this one and recommend you use the eslint-plugin-functional rules I mention above.

The readme here does recommend using it already: https://github.com/danielnixon/eslint-plugin-total-functions#setup

danielnixon avatar Mar 11 '23 05:03 danielnixon