Start a new topic

Interface Base Class Support

I have been creating a DuoCode TypeScript Converter so everything i am talking about is from the point of view of the converter (Unknown classes and interface) so i can think of thinks as just turn an interface into a class and inherit JsInterface.


First... I can't just go changing every interface in the typescript file to a class and inherit JsInterface. This breaks the interface inheritance chain. For example these JQuery interfaces that inherits from multiple other interfaces:

	interface JQueryEventBaseObject extends Event {
	    currentTarget: Element;
	    data: any;
	    delegateTarget: Element;
	    isDefaultPrevented(): boolean;
	    isImmediatePropagationStopped(): boolean;
	    isPropagationStopped(): boolean;
	    namespace: string;
	    originalEvent: Event;
	    preventDefault(): any;
	    relatedTarget: Element;
	    result: any;
	    stopImmediatePropagation(): void;
	    stopPropagation(): void;
	    target: Element;
	    pageX: number;
	    pageY: number;
	    which: number;
	    metaKey: boolean;
	}

	interface JQueryInputEventObject extends JQueryEventBaseObject {
	    altKey: boolean;
	    ctrlKey: boolean;
	    metaKey: boolean;
	    shiftKey: boolean;
	}

	interface JQueryMouseEventObject extends JQueryInputEventObject {
	    button: number;
	    clientX: number;
	    clientY: number;
	    offsetX: number;
	    offsetY: number;
	    pageX: number;
	    pageY: number;
	    screenX: number;
	    screenY: number;
	}

	interface JQueryKeyEventObject extends JQueryInputEventObject {
	    char: any;
	    charCode: number;
	    key: any;
	    keyCode: number;
	}

	interface JQueryEventObject extends JQueryEventBaseObject, JQueryInputEventObject, JQueryMouseEventObject, JQueryKeyEventObject{
	} 


I need to maintain the intended interface usage. So my solution is almost like the suggested one except we use a "Base Interface" like: IObject 

	[Js(Export = false)]
	public interface IObject { }
	public static class Interface
	{
		public static T @new<T>() where T : IObject
		{
			return Js.referenceAs<T>(@"{}");
		}
	}

 

Then my converter can creating bindings like this:

 

	[Js(Name = "Object", Extern = true)]
	public interface JQueryEventBaseObject : IObject, IEvent
	{
		Element currentTarget { get; set; }
		any data { get; set; }
		Element delegateTarget { get; set; }
		[Js(Name = "namespace")]
		string @namespace { get; set; }
		Event originalEvent { get; set; }
		Element relatedTarget { get; set; }
		any result { get; set; }
		Element target { get; set; }
		number pageX { get; set; }
		number pageY { get; set; }
		number which { get; set; }
		boolean metaKey { get; set; }
		boolean isDefaultPrevented();
		boolean isImmediatePropagationStopped();
		boolean isPropagationStopped();
		any preventDefault();
		void stopImmediatePropagation();
		void stopPropagation();
	}

	[Js(Name = "Object", Extern = true)]
	public interface JQueryInputEventObject : IObject, JQueryEventBaseObject
	{
		boolean altKey { get; set; }
		boolean ctrlKey { get; set; }
		boolean metaKey { get; set; }
		boolean shiftKey { get; set; }
	}

	[Js(Name = "Object", Extern = true)]
	public interface JQueryMouseEventObject : IObject, JQueryInputEventObject
	{
		number button { get; set; }
		number clientX { get; set; }
		number clientY { get; set; }
		number offsetX { get; set; }
		number offsetY { get; set; }
		number pageX { get; set; }
		number pageY { get; set; }
		number screenX { get; set; }
		number screenY { get; set; }
	}

	[Js(Name = "Object", Extern = true)]
	public interface JQueryKeyEventObject : IObject, JQueryInputEventObject
	{
		[Js(Name = "char")]
		any @char { get; set; }
		number charCode { get; set; }
		any key { get; set; }
		number keyCode { get; set; }
	}

	[Js(Name = "Object", Extern = true)]
	public interface JQueryEventObject : IObject, JQueryEventBaseObject, JQueryInputEventObject, JQueryMouseEventObject, JQueryKeyEventObject
	{
	}

 

And in the case of having to pass config like options to the api. Since you can't use the C# keyword 'new' ... The new static Interface@new<T> where T : IObject


So you can then:

 

[Js(Name = "Object", Extern = true)]
	public interface JQueryAjaxSettings : IObject
	{
		any accepts { get; set; }
		boolean async { get; set; }
		Func<JQueryXHR, JQueryAjaxSettings, any> beforeSend { get; set; }
		boolean cache { get; set; }
		Func<JQueryXHR, string, any> complete { get; set; }
		bag contents { get; set; }
		any contentType { get; set; }
		any context { get; set; }
		bag converters { get; set; }
		boolean crossDomain { get; set; }
		any data { get; set; }
		Func<any, any, any> dataFilter { get; set; }
		string dataType { get; set; }
		Func<JQueryXHR, string, string, any> error { get; set; }
		boolean global { get; set; }
		bag headers { get; set; }
		boolean ifModified { get; set; }
		boolean isLocal { get; set; }
		any jsonp { get; set; }
		any jsonpCallback { get; set; }
		string method { get; set; }
		string mimeType { get; set; }
		string password { get; set; }
		boolean processData { get; set; }
		string scriptCharset { get; set; }
		bag statusCode { get; set; }
		Func<any, string, JQueryXHR, any> success { get; set; }
		number timeout { get; set; }
		boolean traditional { get; set; }
		string type { get; set; }
		string url { get; set; }
		string username { get; set; }
		any xhr { get; set; }
		bag xhrFields { get; set; }
	}


USAGE:

var settings = Interface.@new<JQueryAjaxSettings>();
settings.username = "mackey";
settings.async = true
jQuery.Ajax(settings);

 


The Interface.@new will basically do the same the JsInterface does for classes (without the dictionary support... don't really want that for strong typed interfaces anyways)... And that is make a native javascript object represented as '{}'... Then when you use the class or interface fields to set properties you'll end up with something like { data: "dello", aux: "more data" } or whatever the field names are... Very cool and LIGHTWEIGHT ... no getter or settings type functions on the internal javascript object. And you maintain the intended

 interface usage


I am suggesting to add something like  

	public interface IObject { }
	public static class Interface
	{
		public static T @new<T>() where T : IObject
		{
			return Js.referenceAs<T>(@"{}");
		}
	}

 

To DuoCode.Runtime... Or something like it.


Thanks A Bunch :)


Even better... Separate IObject and IPropertyBag:


 

	#region DuoCode New Interface
	[Js(Export = false)]
	public interface IObject { }
	[Js(Export = false)]
	public interface IPropertyBag : IObject
	{
		dynamic this[string key] { get; set; }
	}
	public static class Interface
	{
		public static T @new<T>() where T : IObject
		{
			return Js.referenceAs<T>(@"{}");
		}
	}
	#endregion

 

 

UPDATE:


This IObject gives dynamic indexer key support... So can use JUST like JsInterface (without the Add method)


 

	#region DuoCode New Interface
	[Js(Export = false)]
	public interface IObject
	{
		dynamic this[string key] { get; set; }
	}
	public static class Interface
	{
		public static T @new<T>() where T : IObject
		{
			return Js.referenceAs<T>(@"{}");
		}
	}
	#endregion

 interface IMyInterface : Object {}

var myInterface = Interface.@new<IMyInterface>();

myInterface["data"] = "some data";


Works just like JsInterface does for classes... But with native interfaces which is becoming a big deal for me and my typescript converter. Trying to adhere to the TypeScript intended usage of and interface, whether it be to just gather some options like an IGameConfig interface that you can easily instantiate as  a lightweight "Interface Object" or even use as a lightweight property bag as i do for anonymous typescript objects encountered during conversion... No need to make an class for that "property bag" style object... Just just IObject





I want to note that ALL the parsing is by this awesome dude, Michael Cheers. He is working a converter for bridge...  I am using his ReadTypeScriptFile routine to actually parse the typeScript file... Without that little puppy i would not be able to creating any binding via a converter... been doing by hand and that sucks.


Since there is no set rules from DuoCode on creating bindings... i am trying to do all i can to get something working... I think using native LIGHTWEIGHT interfaces is a perfect fit... Only drawback (which is not that big a deal to me) is that you can't use the new keyword ... You have to use something like Interface.@new... If IObject and Interface.@new where part of the DuoCode.Runtime other can use my converted d.cs files (or even the converter itself to make there own C# bindings).


Otherwise everyone will have to use my AjaxGateway Web Application Toolkit (using the -legacy switch) to create classes with no real inheritance support.


Anyways... Think about it... Please!!!



Login or Signup to post a comment