Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Relationship between a TypeScript class and an interface with the same name

I'm having a bit of trouble locating any clear documentation or explanation for the seemingly-special relationship between a TypeScript class and an interface with the same name.

  • What's the significance of an interface with the same name as a class?
  • Why does a class that shares its name with an interface implement that interface automatically?
  • Why does the compiler complain about my getter implementation of a readonly interface field when the class and interface have the same name, but accept the implementation if the names are different?
  • Is there any canonical documentation addressing these questions?

Code:

// Co-named interface and class doesn't like readonly property implementation:  interface Foo {   readonly x: number; // Error: Duplicate identifier 'x'   y: number; }  class Foo {   get x(): number { // Error: Duplicate identifier 'x'     return 0;   }    y = 1; }  // Same as above, but different class name + explicit `implements`  class Bar implements Foo {   get x(): number { // No error!     return 0;   }    y = 1; }  // Duplicating the first example, but explicitly implementing the co-named interface:  interface Baz {   readonly x: number; // Error: Duplicate identifier 'x'   y: number; }  class Baz implements Baz {   get x(): number { // Error: Duplicate identifier 'x'     return 0;   }    y = 1; } 
like image 963
Nathan Ridley Avatar asked Mar 27 '17 20:03

Nathan Ridley


People also ask

Can class and interface have same name?

Case-3: When two interfaces contain a method with the same name, same signature but different return types, in this case, both interfaces can't be implemented in the same class.

What is the relationship between a class and an interface?

A class describes the attributes and behaviors of an object. An interface contains behaviors that a class implements. A class may contain abstract methods, concrete methods. An interface contains only abstract methods.

What happens when two interfaces are created with same name in angular?

No, its an error If two interfaces contain a method with the same signature but different return types, then it is impossible to implement both the interface simultaneously.

What is the difference between a class and an interface TypeScript?

TypeScript class vs.Classes are the fundamental entities used to create reusable components. It is a group of objects which have common properties. It can contain properties like fields, methods, constructors, etc. An Interface defines a structure which acts as a contract in our application.


2 Answers

Interfaces of the same name within a module will be merged:

interface Foo {     x: number; }  interface Foo {     y: string; }  let g = {} as Foo; g.x; // OK g.y; // OK 

A class declaration creates both a constructor function as well as type declaration, which essentially means that all classes can be used as interfaces.

class Bar {     y: number; }  interface IBaz extends Bar { } // includes y: number  class CBaz implements Bar {     y: number = 5; } 

Therefore, having a class and an interface with the same name is equivalent to having two interfaces with the same name, and you will get merge conflicts if both instances of the interface re-declare the same members with different types.

Strangely enough, Typescript will allow for this:

export interface Foo {     readonly x: number; }  export class Foo {     readonly x: number = 3; } 

but it won't allow get x() { return 3; } even though both of those generate as readonly x: number, so I can only imagine that the type checker considers them as different during merging even though they are semantically the same (this is why you can extend the interface and specify the readonly property as a getter function).

like image 76
y2bd Avatar answered Oct 16 '22 07:10

y2bd


This is a limitation specific to accessors, and so far the Typescript team appears unwilling to comment on the issue.

class Foo {   readonly x: number = 0; }  class Bar extends Foo {} interface Bar {   readonly x: 2; }  const bar = new Bar(); bar.x; // type is 2, no error 

The team has commented that "[w]hether a property is implemented as a field or a getter/setter pair is an implementation detail, not part of the type," but this is clearly not the case as of Typescript 4.2:

class Baz extends Foo {     // error: "'x' is defined as a property in class 'Foo',     //         but is overridden here in 'Baz' as an accessor."     get x() {         return 2;     } } 

I have no explanation for the team's responses. The comment that getters/setters are not part of the type system is from 2015 and may simply be outdated.

like image 33
Richard Simões Avatar answered Oct 16 '22 06:10

Richard Simões