Rule proposal: no-unsafe-optional-property-assignment
Author: JoshuaKGoldbergCreated Nov 9, 2022Updated Sep 16, 2026
Labelspackage: eslint-pluginenhancement: new plugin ruleaccepting prs
Before You File a Proposal Please Confirm You Have Done The Following...
- I have searched for related issues and found none that match my proposal.
- I have searched the current rule list and found no rules that match my proposal.
- I have read the FAQ and my problem is not listed.
My proposal is suitable for this project
- My proposal specifically checks TypeScript syntax, or it proposes a check that requires type information to be accurate.
- My proposal is not a "formatting rule"; meaning it does not just enforce how code is formatted (whitespace, brace placement, etc).
- I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).
Description
From https://github.com/danielnixon/eslint-plugin-total-functions:
Optional properties (those with a ? after their name) interact badly with TypeScript's structural type system in a way that can lead to unsoundness. ... This rule bans assignment from one type to another, if:
- the destination type has an optional property, and
- the source type has no matching property (either optional or otherwise).
Note that in order to take the function in here, we'll need to include the fixes proposed in https://github.com/danielnixon/eslint-plugin-total-functions/issues/83.
Fail Cases
type Foo = { readonly foo: string };
type Bar = Foo & { readonly bar?: () => unknown };
const thing = { foo: "foo", bar: "bar" };
const foo: Foo = thing;
const bar: Bar = foo;
if (bar.bar !== undefined) {
bar.bar(); // explodes at runtime
}Pass Cases
type Foo = { readonly foo: string };
type Bar = Foo & { readonly bar?: () => unknown };
const thing = { foo: "foo", bar: "bar" };
const foo: Foo = thing;
const bar = foo;
// @ts-expect-error
if (bar.bar !== undefined) {
// @ts-expect-error
bar.bar(); // explodes, but now we know!
}Additional Info
Forking conversation out from https://github.com/danielnixon/eslint-plugin-total-functions/issues/665.
Source: typescript-eslint/typescript-eslint