-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
TypeScript interfaces for Dependency Injection #3060
Comments
and what is |
That's right, ts does't generate dummy classes for interfaces, (yet ?). |
I would say what you want is #3015 instead :D. this way you get the type information at runtime. |
Not really, my point is about interfaces. If the class member in #3015 was defined as interface, what would get generated for runtime ? |
The structure of the type. See @rbuckton's comment: #3015 (comment) |
I see, if full type information would be available on runtime as @rbuckton proposes, including interfaces, that would solve this need greatly. I really like that proposal. But this specific scenario could be solved with less than that. |
FWIW - I've built a simple DI library for typescript which (ab)uses the fact that there is a separation between the type namespace and the variable namespace. It uses a runtime token which captures the interface type, but which is assigned (by convention) to the same name as the interface it is representing. This allows the dependencies to be declared, registered, and resolved at runtime using the token object, and it's all completely type-safe. |
@sccolbert nice pragmatic workaround. |
@pavelsavara agreed, that would be ideal. |
Currently I have to manually give my interfaces a name. By convention I exploit you can use the same name of the string variable as the interface name. TypeScript works out the difference depending on the context. For example someNameSpace.ISomeInterface is a string normally and is an interface if used with a : I still have to manually match the order to the $inject array with the parameter list in the constructor. I would love to be able to remove the need to manually give the interface a string name and line up the string names with the interface names. I am considering writing my own grunt task to preprocess my TypeScript files to annotate them with the convention I use below. I would like to say how this above issue plays out first. // File: some/name/space/ISomeInterface.ts
} // File: some/name/space/SomeConcrete.ts
} // File: some/name/space/SomeObject.ts
} // File: some/name/space/application.ts someModule = angular.module("someModule", []); |
There are two problems with using TypeScript interfaces for any kind of dependency injection:
interface A { x: number; }
interface B { x: number; }
As such, dependency injection scenarios using decorators will always need some other means for identifying dependencies. This either means using classes (as they have a unique runtime identity), strings, symbols, or some other unique key. @pavelsavara, there are issues with emitting any kind of type handle for interfaces:
The comment that @mhegazy mentioned points to a gist that describes a JSON-like language for describing types. This is more useful for scenarios like runtime type assertions than it is for dependency injection, and would necessitate an additional library just to be able to easily reason over things like union types, etc. As it stands, the approaches that @sccolbert and @brendanowen outline above are a consistent and convention based compromise that looks viable. That said, we will continue to investigate suggestions and alternatives. |
@rbuckton thanks for your research. Few ideas
@sccolbert Ideas in different direction
|
looks like this is already covered in #3015 (comment) |
@mhegazy Sorry to revive this discussion, but I don't understand how the referenced comment relates to the original issue, and I'm facing the exact same problem now. I understand that TypeScript uses a structural type system, but I believe what we need here is not runtime type info about the interface, but an actual runtime reference to the interface type, such that it can be used as a key when resolving the dependency from a dependency injection container. If we go back to the code example at the top, I believe it illustrates the use case quite nicely: We have an We may then have a constructor somewhere that accepts an @Inject()
export class Car {
constructor(public engine: IEngine) {
}
} During app startup we would have registered the preferred implementation: dependencyInjectionContainer.register(IEngine, Engine); This means the constructor will actually receive an instance of However, this will only work if All we need is to have interfaces represented in the same way as abstract classes, as an empty constructor function: var IEngine = (function () {
function IEngine() {
}
return IEngine;
})(); This will allow us to use the interface type as a key, and thus enable this very desirable use case. |
@thomas-darling please see the discussion in #3628 |
I tried to imagine how could I use new Decorator Metadata in order to autowire dependency injection with TS interfaces. Test with tsc 1.5 beta gives me Object constructor instead of interface constructor (perhaps obviously), but that limits the ability of DI container to wire the dependency by type of the interface (as is usual in C#).
This would be the sample.
tcs 1.5beta compiles to this
Ideally the line should be
and IEngine could be dummy class/constructor.
Or it could be string full name of the interface type
I tried to explain this to Angular team before here
angular/angular#135
The text was updated successfully, but these errors were encountered: