-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Introduce a way to enforce a static contract #1263
Comments
Interfaces can't have statics because they only define what the instance side of a type looks like. Why can't you model these types with classes with statics? |
Well would there be any problem in adjusting the responsibility of the interface? I can only see that it would be quite trivial to allow signatures in an interface to be declared with the static keyword, and that this would be semantically quite clear about it's meaning. "Why can't you model these types with classes with statics?" A little unsure about what you are asking here, but as I wrote above the classes needs to have both static and instance members, but I can only enforce a static ((pre-)compile-time) contract on the instance members by using an interface. Even if the framework requires that all these classes implements some static functions, I can not enforce this compile-time. Isn't the only reason that we don't have static interface signatures in languages like C# simply because it makes little sense since we always have to call these explicitly on the specific class anyway? Which is not the case in javascript, where we can have an arbitrary collection of uninstantiated classes/types and handle them just like any other variables. Simply put: We can do static type polymorphism in javascript, but currently we have no way to enforce a contract on this in TypeScript. And my guess is that it would be relatively easy to implement by allowing static signatures in interfaces. |
I'm uneasy on interface PointLIke {
static zero: PointLike;
x: number;
y: number;
}
var x: PointLike = { x: 3, y: 2 }; I have no intuition about whether that should be an error or not. The object literal doesn't have any static members, but the very concept of a static member on an instance just doesn't make any sense. Does This is reasonably easy to fake with something like this: interface HasParse<T> {
parse(s: string): T;
}
class MyDate {
static parse(s: string) { return new MyDate(...); }
}
// Will give an error if MyDate does not fulfill the static contract
var __myDateHasParse: HasParse<MyDate> = MyDate; Obviously that's not entirely optimal (maybe you put the checks in their own file that gets trimmed out of the final build output or something) but it accomplishes the task without burdening |
Hmm... Yes, the static duck-typing makes it a little more rugged terrain obviously. I guess the core of the problem is that an interface both works as a contract for a class and as a duck-typed contract for an arbitrary object. And a class is obviously a different concept from an object instance, and by the introduction of a static signature in the interface, we would introduce a property of the interface that only applies to one of these two usages, thus muddying up the waters a bit. One could think that some options could be
And when I think about it, option 2 isn't all that bad actually. One could think of the implicitly imagined class of the duck-typed object as being in some unobservable quantum-state, fulfilling all and no interfaces at the same time, because we really can't observe it anyway. I think this can make sense considering the nature of js. But maybe it would just look quite strange for a lot of people. And be rarely used anyway. |
I'm still not really clear why you can't use classes to model these contracts you're describing. The interfaces you are complaining about not having access to statics could be classes with statics. |
@danquirk, I'm not sure I follow you (and I don't want to come off as someone complaining, just suggesting that static signatures on interfaces might have value considering the nature of js). Consider this: module Modules
{
export class Bootstrap implements Core.iApplicationModule
{
constructor(private app: Core.Application, private id: string)
{
//...
}
private _self = Bootstrap;
public static get ModuleName() { return "Bootstrap"; } // Can not enforce by contract
public get ModuleName() { return this._self.ModuleName; } // Can enforce by contract
public static get EventSpecification():Core.EventSpecification // Can not enforce by contract
{
//...
}
public EventHandler(event: Core.Models.Event):void // Can enforce by contract
{
//...
}
}
} How would you enforce a contract stating that these static methods must exist in this class? Note that they contain custom logic (not able to put this in a base class) and that they only will be called statically directly on the class. |
My heart is still yearning for static contracts. Do you guys still think it's too complex? It's be such a neat feature considering that classes in JS/TS are first-class elements in Javascript, even if it might fell weird for someone coming from a language like C# |
I think we actually approved this - #420 is Accepting PRs. If that feature is correctly implemented, if you wrote interface HasX {
x: number;
}
class Foo {
static x: string;
}
module Foo implements HasX { } you would get an error about the types of |
I actually like the idea of the static contract, not just allowing static. |
I'm building an application framework in javascript and just porting it over to typescript to use some of that sweet static typing. In my framework I happen to have a concept of a UI module. A UI module is a class and can be instantiated many times in an application. All modules have static definitions of their nature like what events they can trigger and what internal models they make publicly available. The implementation of these modules is a application-implementaional part on a level above the framework codebase, but the framework needs to treat the modules polymorphically (non-instantiated) to read these definitions to set up the application engine accordingly.
If there was the possibility to define static fields in an interface this would take care of making this contract explicit and statically validated for the application developer. But we don't have that. I'm sure that this contract could be enforced by wrapping the module classes in some kind of factory pattern or other contraptions, but I'm honestly not very attracted to that.
Wouldn't it be neat if we can enforce a static contract in typescript, considering the dynamic nature of the underlying javascript where this kind of static type polymorphism isn't all that weird?
The text was updated successfully, but these errors were encountered: