Discussion: Extending core ESLint rules to "just work" with TS-specific nodes #77
Description
In agreement with @nzakas, I wanted to start a discussion here which summarises the findings so far on which core ESLint rules currently have issues with TypeScript-specific concepts, such as interfaces and decorators.
We do have a few options open to us with regards to making this all work (and the eslint-plugin-typescript
plugin will still have its place regardless), but we are in agreement that it would be awesome if we did not have to duplicate any existing rules where all we are trying to do is match the same functionality as on standard JS nodes.
I have been running all of the core rules over a large TypeScript codebase (definitely not an exhaustive use of TypeScript features in there, but it's a great start) and noted the following, some of which is fairly subjective:
Rule: camelcase
We have the ability to control whether or not camelcase
will apply to object properties, e.g.
"camelcase": ["error", { "properties": "never" }]
Opinion: We should be able to do this for TypeScript interfaces properties too
Rule: keyword-spacing
We can enforce spaces before and after keywords like so:
"keyword-spacing": ["error", { "before": true, "after": true }]
Opinion: We should be able to make type "casting" exempt from this in some way
E.g. I had this example:
<models.ICreativeTemplate>this.currentCreative.template
...where I would not want to put a space between the >
and this
keyword, but the rule naturally wants me to.
Rule: no-undef
With TypeScript, we are supporting class properties and interfaces. These are both causing false negatives with no-undef
:
class A {
foo = true
}
/* ESLint:
error, 'foo' is not defined
interface MyInterface {
bar: string,
baz: number
}
/* ESLint:
error, 'MyInterface' is not defined
error, 'bar' is not defined
error, 'baz' is not defined
It is very likely there are more TypeScript features that will cause the same, but currently those two are so noisy in my codebase that it is not worth investigating further.
This was also reported here: #75
Rule: no-used-vars
There are a couple of things causing false negatives with no-unused-vars
:
(1) Class properties created via the constructor, and then later used in a method
class SomeClass {
constructor(
private foo: string
) {}
someMethod() {
return this.foo
}
}
/* ESLint:
error, 'foo' is defined but never used
(2) Decorators
import { Injectable } from 'foo-framework'
@Injectable()
class Service {}
/* ESLint:
error, 'Injectable' is defined but never used
This was also reported here: #55
Rule: no-useless-constructor
Using the same class property assignment within a constructor example from above, we will also get a false negative on no-useless-constructor
class SomeClass {
constructor(
private foo: string
) {}
someMethod() {
return this.foo
}
}
/* ESLint:
error, Useless constructor
Rule: space-infix-ops
This rule is basically unusable, given the type annotation syntax :
Rule: semi
It was pointed out here #61 (comment) that TypeScript-only statements will currently not be detectable as needing a semi-colon.
E.g.
"semi": ["error", "always"]
type Result<T> = Success<T> | Failure
/* ESLint:
(No error reported, but should point out missing semi-colon)