Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class declarations should implicitly implement interfaces #340

Closed
mwisnicki opened this issue Aug 2, 2014 · 6 comments
Closed

Class declarations should implicitly implement interfaces #340

mwisnicki opened this issue Aug 2, 2014 · 6 comments
Labels
Committed The team has roadmapped this issue Suggestion An idea for TypeScript

Comments

@mwisnicki
Copy link

http://typescript.codeplex.com/workitem/1125

Following should be allowed:

interface IFoo {
    foo();
}

declare class Foo implements IFoo {}

If abstract classes are added in the future, they would inherit all interface methods as abstract (like in Java).

@Bartvds
Copy link

Bartvds commented Aug 2, 2014

+1 It would remove a lot of code duplication on declaration files.

@basarat
Copy link
Contributor

basarat commented Aug 2, 2014

👍

The kind of thing you don't know you need till you see it suggested. In the absence of this many times DT PR's break tests because they need to go to all the places and add these members. (which is fine-ish)

More importantly for something like spacepen (used by atom.io) that implements JQuery we (the wise @vvakame) just decided not put them in and leave it in a comment (otherwise we would need to fix up the definition everytime someone added a new JQuery plugin definition).

https://github.com/borisyankov/DefinitelyTyped/blob/e9b0f608b1ca18344b2a916048594c8f30b0df10/space-pen/space-pen.d.ts#L52

declare class View /* implements JQuery */ {

@basarat
Copy link
Contributor

basarat commented Aug 2, 2014

If its decided to add this, I also have breaking change proposal. I think the following should be prevented and give an error as shown:

interface IFoo {
    foo();
}

declare class Foo implements IFoo {
    foo(); // Error: Already has member foo
}

That will make implementing this feature easier and consistent.

@mwisnicki
Copy link
Author

Why ? It's allowed for classes:

declare class Foo {
    foo();
}

declare class Foo2 extends Foo {
    foo();
}

It's quite useful - you can put additional documentation on Foo2.foo this way.

@RyanCavanaugh
Copy link
Member

The problem is that if you assume classes have their declared interface's members, it becomes very unclear/confusing what it means if you explicitly write those members:

/* Input code */
interface SomeInterface1 {
    getThing(x: string): Element;
}

interface SomeInterface2 {
    getThing(x: number): HTMLElement;   
}

declare class SomeClass implements SomeInterface1, SomeInterface2 {
    getThing(x: any): HTMLCanvasElement;
}

/* What does the definition of SomeClass mean? */

// First answer: Same thing it meant in TypeScript 1.0, because
// this doesn't justify a breaking change
module Alpha {
    declare class SomeClass implements SomeInterface1, SomeInterface2 {
        getThing(x: any): HTMLCanvasElement;
    }
}

// Second answer: The class implementation is just another
// signature, so append it to the list of signatures we got from
// the interfaces
module Beta {
    declare class SomeClass implements SomeInterface1, SomeInterface2 {
        getThing(x: string): Element;
        getThing(x: number): HTMLElement;   
        getThing(x: any): HTMLCanvasElement;
    }
}

// Third answer: The class implementation should come first because
// it's the most important one (even though this creates unreachable signatures)
module Gamma {
    declare class SomeClass implements SomeInterface1, SomeInterface2 {
        getThing(x: any): HTMLCanvasElement;
        getThing(x: number): HTMLElement;   
        getThing(x: string): Element;
    }
}

// Fourth answer: This is disallowed?
module Delta {
    /* Breaking change, SomeClass is an error */
}

Then, under the proposal:

/* Input code, changed slightly */
interface SomeInterface1 {
    getThing(x: string): Element;
}

interface SomeInterface2 {
    getThing(x: number): HTMLElement;   
}

declare class SomeClass implements SomeInterface1, SomeInterface2 { }

/* What does the definition of SomeClass mean? */

// First answer: this is an error because SomeInterface1 and SomeInterface2
// have conflicting members
module Alpha {
    /* error */
}

// Second answer: The class is assumed to have both overloads
module Beta {
    declare class SomeClass implements SomeInterface1, SomeInterface2 {
        getThing(x: string): Element;
        getThing(x: number): HTMLElement;   
    }
}

// Third answer: Something else?
module Gamma {
    declare class SomeClass implements SomeInterface1, SomeInterface2 {
        /* ? */
    }
}

@RyanCavanaugh
Copy link
Member

Note that in the latest version of TypeScript, you can use class/interface merging to do this:

interface Foo {
    a: number;
}

interface Baz extends Foo { }
class Baz {
    constructor() {
        console.log(this.a); // no error here
    }
}

hat tip @jeffreymorlan for reminding me of this

@RyanCavanaugh RyanCavanaugh added Committed The team has roadmapped this issue and removed Canonical This issue contains a lengthy and complete description of a particular problem, solution, or design Declined The issue was declined as something which matches the TypeScript vision Too Complex An issue which adding support for may be too complex for the value it adds labels Feb 17, 2016
@microsoft microsoft locked and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Committed The team has roadmapped this issue Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants