In TypeScript, there are two ways to define properties or parameters that are potentially undefined:
undefined: Adding | undefined in the property type makes the property required, but can be
undefined. Use this syntax when you want to be explicit that an object should provide that property, in which case the TypeScript
compiler will not allow omitting it.
interface Person {
name: string;
address: string | undefined;
}
let John = { name: "John", address: undefined };
? after its name): The property is optional, which means that an object can omit it and let the
TypeScript compiler provide it as being undefined.
interface Person {
name: string;
address?: string;
}
let John = { name: "John" };
This rule checks for optional property declarations that use both the ? syntax and unions with undefined, including cases
where undefined is introduced through a type alias — even through alias chains or generic types.
interface Person {
name: string;
address?: string | undefined; // Noncompliant: using both syntaxes is redundant
}
type MaybeString = string | undefined;
interface Contact {
email?: MaybeString; // Noncompliant: the alias already includes 'undefined'
}
type Maybe<T> = T | undefined;
interface Widget {
label?: Maybe<string>; // Noncompliant: the generic alias resolves to 'string | undefined'
}
type NumberOrUndefined = number | undefined;
type Attribute = string | NumberOrUndefined;
interface Form {
value?: Attribute; // Noncompliant: 'undefined' is reachable through the alias chain
}
Choose one of the syntaxes to declare optional properties and remove the other one. Consider using only | undefined if you want to
make the property explicit in the object.
interface Person {
name: string;
address?: string;
}
type MaybeString = string | undefined;
interface Contact {
email: MaybeString;
}
type Maybe<T> = T | undefined;
interface Widget {
label: Maybe<string>;
}
type NumberOrUndefined = number | undefined;
type Attribute = string | NumberOrUndefined;
interface Form {
value: Attribute;
}
The rule does not raise any issues when the TypeScript compiler option exactOptionalPropertyTypes is enabled because this option
ensures that undefined does not become redundant in this context.
Detection of undefined types hidden behind type aliases requires the TypeScript compiler option strictNullChecks (or
strict) to be enabled. When neither option is set, the rule only detects undefined types that appear directly in the
property’s type annotation.
The rule does not raise an issue when undefined is only reachable through a type defined in an external library (for example,
React.ReactNode). This also applies when an indexed access refers to an optional property declared by an external library:
import type { TextFieldProps } from '@mui/material';
interface Props {
size?: TextFieldProps['size']; // Compliant by exception: 'undefined' comes from an external declaration
}
In this case, there is no | undefined to remove from the annotation because the undefined is hidden behind the indexed
access, and removing ? would make size required. Since the undefined originates from an external type
declaration that the user cannot modify, flagging the property would produce a false positive. This exception is limited to external declarations: the
same pattern on a locally declared type is still reported, as the optional property it refers to can be changed.