Some time after this rule was written, Anders Hejlsberg opened a PR that preserves type aliases for union and intersection types. That PR's changes should included in TypeScript 4.2, so when that version is released, the reasons for preferring interfaces might be less compelling.
This rule effects failures for type alias declarations that can be declared as interfaces.
Honestly, my take is that it should really just be interfaces for anything that they can model. There is no benefit to type aliases when there are so many issues around display/perf.
We tried for a long time to paper over the distinction because of people's personal choices, but ultimately unless we actually simplify the types internally (could happen) they're not really the same, and interfaces behave better.
— Daniel Rosenwasser October 22, 2020
Examples of incorrect code for this rule:
type Person = {
age: number;
name: string;
};
type Comparator<T> = (left: T, right: T) => number;
Examples of correct code for this rule:
interface Person {
age: number;
name: string;
}
interface Comparator<T> {
(left: T, right: T): number;
}
type Worker = Person | Robot;
type DeepReadonly<T> = {
readonly [P in keyof T]: DeepReadonly<T[P]>;
};
This rule accepts a single option which is an object with allowIntersection
and allowLocal
properties.
The allowIntersection
option defaults to true
. If set to false
, the rule will disallow type aliases that are intersections:
interface Name { name: string; }
interface Age { age: number; }
type T = Name & Age;
and the rules fixer will replace the type alias declaration with an interface:
interface Name { name: string; }
interface Age { age: number; }
interface T extends Name, Age {}
The allowLocal
option determines whether local - i.e. non-exported - type aliases that could be declared as interfaces are allowed. By default, they are not.
{
"etc/prefer-interface": [
"error",
{
"allowIntersection": true,
"allowLocal": true
}
]
}
- The Twitter thread from which the above quote was taken.
- Prefer Interfaces