π Disallow unreadable new expressions.
π« This rule is disabled in the following configs: β
recommended, βοΈ unopinionated.
Disallow member access directly from new expressions and disallow complex constructor expressions.
This rule allows identifier constructors and static member constructors. Split the constructor call and member access into separate statements, or assign a complex constructor expression to a clear name before using new.
new is unusually precedence-sensitive: new with an argument list and new without one parse at different levels, so a pair of parentheses flips the meaning.
new Foo().Bar; // `(new Foo()).Bar`: read `Bar` off the instance
new Foo.Bar(); // `new (Foo.Bar)()`: construct `Foo.Bar`These look almost identical yet do opposite things, and since new Foo equals new Foo(), the parentheses do not reliably tell you which part new applies to. Even in new Date(string).getTime() you have to confirm those parens are an argument list and not a precedence group, and new (foo().Bar)() is harder still. Class-name casing does not help: the language does not enforce it, so reading the code correctly should not depend on it.
Splitting the expression removes the guesswork: name what you build, then use it. It reads just as well, and the name pays off the moment you reuse, log, or breakpoint the instance.
// β
const bar = new Foo().getBar();
// β
const foo = new Foo();
const bar = foo.getBar();// β
const Bar = new Foo().Bar;
// β
const foo = new Foo();
const Bar = foo.Bar;// β
const bar = new (foo().Bar)();
// β
const {Bar} = foo();
const bar = new Bar();// β
const bar = new foo[Bar]();
// β
const Bar = foo[Bar];
const bar = new Bar();