Sometimes it's useful to have methods with properties attached:
Foo.prototype.bar = bar;
bar.tag = 123;
The corresponding interface could look like:
interface Foo {
@tagged
bar(): void;
}
Please log issues with enough information for us to understand what's going on. How did tagged get turned into tag? Where did 123 go? What is stopping you from writing this code today?
@tagged is a decorator that is when applied to a method, adds a property called tag to it:
function tagged(proto, name, d: TypedPropertyDescriptor<any>) {
d.value.tag = 123;
}
class FooImpl {
@tagged
bar() {
console.log("bar");
}
}
const foo = new FooImpl;
foo.bar.tag == 123;
Then if we try to come up with an interface definition for FooImpl we will find that it's difficult to express the fact that some methods in our interface have the tag property:
interface Foo {
/** This method has .tag property attached. */
bar(): void;
}
Having such a comment isn't good enough and the types intersections help us solve the problem to some extent:
type Tagged<T extends Function> = T & { tag: number };
interface Foo {
bar: Tagged<() => void>;
}
This is pretty good until we decide to extend our class with an overloaded version of bar and the overloaded version needs to appear in a separate file that extends the interface:
/// [file1.ts]
interface Foo {
bar: Tagged<() => void>;
}
/// [file2.ts]
interface Foo {
bar: Tagged<(abc: string) => void>;
}
But this doesn't work because bar is declared as a member, not as a method. With an ambient decorator it should be possible:
/// [file1.ts]
interface Foo {
@tagged
bar(): void;
}
/// [file2.ts]
interface Foo {
@tagged
bar(abc: string): void;
}
a decorator on an interface does not make much sense. it is an implementation detail, and has no impact on the type anyways. adding the tag to the interface makes it impossible for you to implement it, as again the decorator does not do any type mutations. i think what you are looking for is: #4881
@mhegazy Can you elaborate on why this doesn't make much sense?
One use case could be something like Retrofit for Android:
interface MyAPI {
@GET("/example")
getExampleData(): Observably<ExampleModel>;
@POST("/example")
postExampleData(body: ExamplePostModel): Observable<ExamplePostResponseModel>;
}
Do you have any idea how this could be done without interface member decorators?
Both of those decorators imply some sort of implementation/run-time meta data coupled with an interface. They are fully erasable type information, not implementations. What makes sense about that?
Do you have any idea how this could be done without interface member decorators?
Decorators on a class implementation?
Any progress? I need them exactly for this purpose https://github.com/Microsoft/TypeScript/issues/6818#issuecomment-311903830
Most helpful comment
@mhegazy Can you elaborate on why this doesn't make much sense?
One use case could be something like Retrofit for Android:
Do you have any idea how this could be done without interface member decorators?