Tslint: interface-over-type-literal shouldn't be recommended

Created on 25 Sep 2017  ·  18Comments  ·  Source: palantir/tslint

Yes, I know the Typescript docs say

Because an ideal property of software is being open to extension, you should always use an interface over a type alias if possible.

but seriously, if I am making a simple type with zero intention of ever using it as an extendable thing, it makes no sense to code it as an interface.

API Breaking Change Enhancement

Most helpful comment

I do know that I can override it, but I feel pretty strongly that the recommendation is incorrect.

Here's my view of it. There are many cases where an interface cannot be used for a type alias. You can only use an interface to type an object literal. If I am to follow the recommended best practices, then in a particular class file where I may have several type aliases, some will be type aliases and some will be interfaces. Someone stumbling upon this class will wonder what the heck is going on and if I am intending the interfaces to be implemented/extended somewhere, or to at least be expecting it to be a possibility.

It would be much cleaner in my opinion for me to use a type alias for a type alias and an interface for an interface, rather than substitute one for the other in some cases just because interfaces have some extra capability (that I don't need if all want is a type alias).

I suppose I should write up an issue against the typescript docs, which I will do, but I think some engineering judgement can be applied here rather than implement a rule just because the docs say you should.

All 18 comments

Sorry, I don't get what you mean. Is this a feature request or a bug report?

The default value for interface-over-type-literal in recommended.ts is true. I believe it should be false. Not sure if that constitutes a feature request or a bug :-)

After all the recommended preset is opinionated. It incorporates best practices and suggestions like the one you posted above.
When extending a preset, you can override the recommendation and tune the configuration to your needs.

Anyways, disabling the rule would be a breaking change. So don't expect any change before the next major version.


To clarify: interface-over-type-literal only complains about type alias declarations.

type Foo = {foo: number}; // The rule disallows this
interface Foo {foo: number} // and fixes it to this

let obj: {foo: number}; // This is still allowed

Since a type alias and an interface can be used (almost) interchangeably, I don't see why you would prefer the type alias.

On a related note: interfaces used to be cached while anonymous types like type aliases were recomputed for ever usage. So using type aliases could significantly increase compile time.
That performance gap will be almost gone with the next typescript version.

I do know that I can override it, but I feel pretty strongly that the recommendation is incorrect.

Here's my view of it. There are many cases where an interface cannot be used for a type alias. You can only use an interface to type an object literal. If I am to follow the recommended best practices, then in a particular class file where I may have several type aliases, some will be type aliases and some will be interfaces. Someone stumbling upon this class will wonder what the heck is going on and if I am intending the interfaces to be implemented/extended somewhere, or to at least be expecting it to be a possibility.

It would be much cleaner in my opinion for me to use a type alias for a type alias and an interface for an interface, rather than substitute one for the other in some cases just because interfaces have some extra capability (that I don't need if all want is a type alias).

I suppose I should write up an issue against the typescript docs, which I will do, but I think some engineering judgement can be applied here rather than implement a rule just because the docs say you should.

The use of interface keyword for structures should really be discouraged in my opinion. This rule does exactly the opposite, so there is no way in hell this can be considered a best practice.

This is one of the things typescript got wrong in my opinion, this is confusing the concept of interface, whose semantics in all other typesafe languages I've used, means "a collection of methods/functions/callable things", with object signature/duck type. The use of interface should be more restrictive, and I would really welcome a TSLint rule "interface-must-declare-only-functions", or a less restrictive "interface-must-declare-at-least-one-function"

Pure structures should be declared using the type operator and extended using the & operator. And the name should start with "T" :-)

@navels I agree with your feedback, I think tslint:recommended should remove this overly-opinionated rule configuration as a breaking change in the next major version

how can I override this option?

@sibelius in your tslint.json, under "rules", mark it as false:

{
    "extends": ["tslint:recommended"],
    "rules": {
        "interface-over-type-literal": false
    }
}

Note that this issue is tracking disabling the rule in the recommended ruleset. If you have general questions on TSLint, please use either StackOverflow or Gitter.

Here someone talk about this subject https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c

About overwrite the rule, I would prefer the option to force me use type instead of interface or even better, force me to use type only if I'm defining a Props or State in my react component.

I've been writing less and less OOP code to the point that I'm not using it at all in my current project.
I wouldn't want beginners to be nudged towards it.

@dandrei and I use Interfaces only, when I want to describe functions (I use no OOP too).

Yeah, this one's definitely wrong and IMO should not be part of the recommended, or at least not auto-fixed so we can disable it before it clobbers our types.

The recommendation actually breaks code. Consider:

type Foo = {
  foo: string
}

interface IndexedObject {
  [key: string]: string
}

function useIndexedObject(object: IndexedObject) {}

const foo: Foo = {foo: "foo"}
useIndexedObject(foo)

The above code works. Until tslint --fix is applied and changes type Foo to interface Foo, the last line produces the error:

Argument of type 'Foo' is not assignable to parameter of type 'IndexedObject'.
  Index signature is missing in type 'Foo'.

IMO, any rule that breaks code should not be a recommendation. Heck, it shouldn't even be a rule if it has the potential to break code.

Not only that, but it also causes the "interfaces must start with 'I'" rule.

error TS2344: ...
Index Signature is missing in type 'SOME INTERFACE'.

so I have to use type.

If your apps have a lot of type usage, it is a good indicator of violations of SOLID principles.

Removing the Type: Breaking Change label per #4811. Now accepting PRs!

So why is it called TypeScript, when it should be named InterfaceScript?! 🤣

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rajinder-yadav picture rajinder-yadav  ·  3Comments

CSchulz picture CSchulz  ·  3Comments

DanielKucal picture DanielKucal  ·  3Comments

avanderhoorn picture avanderhoorn  ·  3Comments

SwintDC picture SwintDC  ·  3Comments