Could extending generic parameter be possible?

Topics: Language Specification
Mar 25, 2014 at 6:26 PM
Monkey patching objects is a common thing in the Javascript world and TypeScript allows you to create interfaces that extend other interfaces so that you can do it in a type safe way. However you have to explicitly define new interfaces for each type of object being patched. It would be very interesting if instead we could do something like the following.
interface Patched<T> extends T {
    patchMethod1();
    patchMethod2();
    patchMethod3();
}

declare function<T>patchMe(object: T): Patched<T>;

var a = {foo: 'bar'};
var b = patchMe(a);
b.patchMethod1(); 
b.patchMethod2();
b.foo 
The precise use case that raised this is how restangular works. It gets the object from an API but it adds a series of methods to it for making subsequent calls to the API easier. What I have been doing so far is the following:
// Restangular type definition
interface RestangularElement {
    get(...): Promise...;
    put(...): Promise...;
    //...
}
interface Company {
    id: number;
    name: string;
}
interface User {
    id: number;
    name: string;
    companyId: number;
}

interface RestCompany extends Company, RestangularElement {}
interface RestUser extends User, RestangularElement {}

Restangular.one('user', 1).get((user: RestUser) => {
    console.log('hello ' + user.name);
    user.companyId = 4;
    return user.put();
});
and what I think it would be nice we could do is
interface RestangularElement<T> extends T {
    get(...): Promise...;
    put(...): Promise...;
    //...
}

interface Company {
    id: number;
    name: string;
}
interface User {
    id: number;
    name: string;
    companyId: number;
}

Restangular.one('user', 1).get((user: RestangularElement<User>) => {
    console.log('hello ' + user.name);
    user.companyId = 4;
    return user.put();
});
without having to explicitly declare an extra interface for each object in the API.

I hope the example is clear enough. What do you guys think?
Mar 26, 2014 at 12:12 AM
Edited Mar 26, 2014 at 12:15 AM
Note: You can also do this:
declare class A {
    get(...): Promise...;
    put(...): Promise...;
    //...
}

interface Company extends A {
    id: number;
    name: string;
}

interface User extends A {
    id: number;
    name: string;
    companyId: number;
}
http://goo.gl/6kjlvp
Mar 26, 2014 at 12:51 AM
The problem with this approach is that the type definition for the API is tied to restangular and you lose the ability to create Company or User objects since you will need to implement all class A methods and properties.
Mar 26, 2014 at 2:27 AM
Oh I see what you are trying to do now, sorry. Sort of like an "on the fly" merger of two interfaces. Similarly, I find many times I would like to apply two interfaces to an object as a merged type in itself, without declaring the resulting type. Something like: "var obj : <Interface1, Interface2> = ...;" or "var obj : Interface1 extends Interface2 = ...;".
Mar 26, 2014 at 12:32 PM
Exactly, that is what I meant.