TypeScript definitions
romanov opened this issue · comments
Is there any plan to release definitions for TypeScript?
Hi romanov,
this is interesting but currently not planned. However it might be easy to achieve based on the control metadata. I'll leave this ticket open as inspiration for a possible enhancement.
Regards
Andreas
I would definitely be interested in a TypeScript definition. We've been generating one using a JSDoc plugin, but it's error prone and requires a lot of manual intervention. Using the control files or something similar would much more reliable.
I am interested as well.
Hi Sirs,
I'd like to ask Andreas(@akudev) if this thing has an official spin and if it's somehow going forward.
Since UI5 is an enterprise solution and TypeScript has many more good features than ES6 for team development it could even be more interesting if UI5 could adopt TS as its underlying OOP System.
Thank you & SAP for all the good code.
-- Roberto
http://www.exedraos.com
@RobertoMalatesta
Since typescript is a superset of javascript, you can use it today.
Regarding Typings, @stephenfhunt mentioned a jsdoc plugin (which one? ) or you can lazily build a definition file yourself from the api doc (copy,paste,regex). Feel free to use mine at afrische/ui5.d.ts .
Additionaly, you may want to use es6/ts classes instead of ui5's module system. Then, controllers(and jsviews) should look something like this
namespace A.B {export class CController {...} }sap.ui.controller("A.B.C" , new A.B.CController());
and other "classes" like this
namespace A.B {
export const Component = sap.ui.core.UIComponent.extend("A.B.Component", {
metadata: {
manifest: "json"
},
init: function () {
sap.ui.core.UIComponent.prototype.init.apply(this, arguments);
this.getRouter().initialize();
}
})
}
jQuery.sap.declare("A.B.Component", false);
Hi @afrische, your github project looks promising and useful, I will follow it.
On typing: by using Generics,Interfaces and Classes UI5 could get a cleaner construction/implementation system, using Abstract Data Types and Contract-based Programming, leveraging TS concepts, syntax and tools.
As an example: in the code you quoted, having to pass an Interface instead of a JSON Object would lead to a more documented and safer code.
It will be more manageable especially in large development teams.
Grüße
R
+1 for TypeScript.
We have 200k+ lines of code of TypeScript and it fully compiles in 8 seconds. And it is just amazing how Javascript can became so manageable with such a beautiful language as TypeScript. Definitions, Module system, Structural subtyping, Type safety, Type inference, and ES6 just now.
Few years and we'll forget about javascript (same as x86 assembler).
+1
+1 - would love to see .tsd files for OpenUI5!
not only .tsd, but TSX/JSX could be used for declarative UI there is no need for custom XML UI schemas in 2016.
+1 for typescript definitions.
I guess it should be possible to generate those from the JSDoc. This way private API would be excluded from the types automatically.
the typsescript defintion file would automatically enable intellisense for UI5 coding in Visual Studio Code since this is there mechanism to retrieve type information: https://code.visualstudio.com/docs/languages/javascript#_intellisense
There is a (highly experimental) GitHub project which generates TypeScript definition files from JSDoc. I haven't tried it yet, but seems promising nonetheless: https://github.com/englercj/tsd-jsdoc
For me the angular project https://github.com/angular/dgeni-packages seems to be the most promising.
Mark Schmale also hacked together a script to extract type definitions from the api.json:
https://github.com/themasch/ui5-typescript-fetcher
hth
Hello,
I started writing a typescript converter in .NET, which using the information of the api doc rest service (as themasch's typescript fetcher does).
https://github.com/apazureck/openui5TypescriptGenerator
The extracted files are in my fork of afrische's typescript declaration repo:
https://github.com/apazureck/ui5.d.ts/tree/master/UI5Application1/UI5Application1/Scripts/typings/ui5
It declares classes, enums (string literals) and typedefs. I put in some text fields to replace types and there is a version selector for deprecated methods.
I am a beginner in both, typescript and ui5 and I get a lot of errors now. I fixed the most obvious stuff, but now I get compiler errors regarding inheritance inconsistencies and therefore, I have to have more experience with this stuff. Perhaps someone (hopefully more experienced than me) has the time to have a look at the files and can help me improve the procedure. Help much appreciated.
I am missing all the constructor parameter declarations so far and I am also not sure, if the documentation is always correct, as I got some interesting type specifications out of the json file?
Cheers
Little update:
The TS parser works now and I created definition files for the whole project. Would it be possible to adjust your documentation to fit better to type script? There are some incosistencies in the type descriptions.
Here some examples I had to replace:
Annotation:
left side is input type I got from the API.json file, right hand side is the replacement.
- * : any
- any[] : any[]
- array : any[]
- Array : any[]
- array.<array.> : string[][]
- arraybuffer : any
- bAlwaysShow : boolean
- blob : any
- Boolean : boolean
- CalendarAppointment : any
- Control : sap.ui.Core.Control
- createDefaultContent : any
- date : any
- Date : any
- DomNode : any
- DOMNode : any
- domRef : any
- DomRef : any
- DOMRef : any
- DomRef[] : any[]
- element : any
- Element : any
- Element[] : any[]
- EntityType : any
- Error : any
- event : any
- float : number
- function : any
- Generator : any
- HTMLElement : any
- int : number
- int[] : number[]
- integer : number
- InvisibleControl : any
- jQuery : any
- jQuery.promise : any
- jQuery.Promise : any
- jQuery.sap.log : jQuery.sap.log.Logger
- map : any
- Map : any
- MenuButton : any
- null :
- Number : number
- Number[] : number[]
- objec : any
- object : any
- Object : any
- object[] : any[]
- ObjectNumber : number
- oWindow : any
- Promise : any
- regexp : string
- sap.m.Control : sap.ui.core.Control
- sap.m.P13nConditionOperation : any
- sap.m.P13nConditionOperation[] : any[]
- sap.m.TabStripItem : any
- sap.ui.base.ManagedObjectMetadata : any
- sap.ui.base.ManageObject : sap.ui.base.ManagedObject
- sap.ui.core.Controller : sap.ui.core.mvc.Controller
- sap.ui.core.InvisibleControl : any
- sap.ui.demokit.UI5EntityCueCardStyle : any
- sap.ui.model.analytics.odata4analytics.ParametrizationRequest : any
- sap.ui.suite.TaskCircleColor : any
- sap.ui.test.qunit : any
- ScrollEnablement : sap.ui.core.delegate.ScrollEnablement
- sting[] : string[]
- String : string
- string[] : string[]
- String[] : string[]
- TablePersoController : any
- TablePersoDialog : any
- Touch : any
- TouchList : any
- true : boolean
- undefined : any
- Window : any
Cheers
Some of the entries are obviously misspelled types and need to be fixed, others seem to be valid. I took a quick look and came to the following classification:
Typos, JSDoc Syntax, Inconsistencies (fix)
- bAlwaysShow : boolean ✔️
- blob :
anyBlob ✔️ - arraybuffer :
anyArrayBuffer ✔️ - date :
anyDate ✔️ - event :
anyeither jQuery.Event or sap.ui.base.Event ✔️ - integer :
numberint (convention used by UI5) ✔️ - sap.ui.base.ManageObject : sap.ui.base.ManagedObject ✔️
- objec : any ✔️
- oWindow :
anyWindow ✔️ - sting[] : string[] ✔️
- sap.ui.model.analytics.odata4analytics.ParametrizationRequest :
anysap.ui.model.analytics.odata4analytics.ParameterizationRequest ✔️ - regexp :
string_RegExp_ ✔️ - element :
anyElement ✔️ - jQuery.sap.log : jQuery.sap.log.Logger ✔️ this was an interesting case: JSDoc allows a type reference that point's to static field, but for a typed language this doesn't make sense. Changing it to the type in this specific case didn't hurt. For
true
,undefined
andnull
it is more difficult as we don't want to lose the information - DomNode, DOMNode, domRef, DomRef, DOMRef :
anyElement or HTMLElement, to be discussed
Unqualified References or Wrong Package (fix)
- CalendarAppointment :
anysap.ui.unified.CalendarAppointment ✔️ - Control : sap.ui.Core.Control ✔️
- EntityType :
anysap.ui.model.analytics.odata4analytics.EntityType ✔️ - InvisibleControl :
anysap.ui.core.InvisibleText ✔️ - MenuButton :
anysap.m.MenuButton ✔️ - ObjectNumber :
numbersap.m.ObjectNumber ✔️ - sap.m.Control : sap.ui.core.Control ✔️
- ScrollEnablement : sap.ui.core.delegate.ScrollEnablement ✔️
- TablePersoController :
anysap.m.TablePersoController ✔️ - TablePersoDialog :
anysap.m.TablePersoDialog ✔️ - sap.ui.core.Controller : sap.ui.core.mvc.Controller ✔️
- sap.ui.core.InvisibleControl :
anysap.ui.core.InvisibleText ✔️
Visibility / Missing Documentation (should be fixed, but not necessarily as suggested)
- sap.ui.base.ManagedObjectMetadata :
anymade public ✔️ - sap.ui.suite.TaskCircleColor :
anymisplaced JSDoc doclet ✔️ - sap.ui.demokit.UI5EntityCueCardStyle :
anymisplaced JSDoc doclet ✔️ - sap.m.TabStripItem :
anytype is private, made all usages private ✔️ - sap.m.P13nConditionOperation : any to be discussed, seems to be intended for internal use only
- sap.m.P13nConditionOperation[] : any[] to be discussed, seems to be intended for internal use only
Native APIs (see e.g. https://developer.mozilla.org/en-US/docs/Web/API), Thirdparty
- Element
- Element[]
- HTMLElement
- Error
- Object
- Promise
- Touch
- TouchList
- Window
- jQuery
UI5 basic types / JSDoc convention (won't fix, map generically)
- float : number in the documentation and ManagedObject definitions, we use int and float to identify different use cases for number
- int : number in the documentation and ManagedObject definitions, we use int and float to identify different use cases for number
- int[] : number[] in the documentation and ManagedObject definitions, we use int and float to identify different use cases for number
- function : any
- object :
anyObject might be better. At least for UI5 properties the type object restricts values to simple objects. - object[] :
any[]Object[] see above - undefined : any usually, undefined is used in addition to another type. It then means: undefined is an allowed / expected value, even if the other type would not allow it
- string[] : string[] ???
- array : any[]
- Array : any[]
- array.> : string[][]
Correct? (not clear why they had to be mapped)
- sap.ui.test.qunit : any
- createDefaultContent :
anythis is a JSDoc typedef
Open
- Boolean : boolean // Reference to object wrapper might be intended or not
- true : boolean
- map : any // Google Closure Compiler suggest a different syntax for maps
- Map : any // Google Closure Compiler suggest a different syntax for maps
- null : // right hand side missing? Otherwise 'null' is as valid as 'undefined'
- Generator : any // how to document ES6 generators ?
- Number : number // Reference to object wrapper might be intended or not
- Number[] : number[] // Reference to object wrapper might be intended or not
- String : string // Reference to object wrapper might be intended or not
- String[] : string[] // Reference to object wrapper might be intended or not
- jQuery.Promise : any
- jQuery.promise : any
[UPDATE] List above updated with fixes, added some more comments.
Hello,
maybe could be used https://github.com/lastsys/scalajs-openui5 project where everything is typed.
Sure it is in .scala, but could be converted into typescript definitions.
Thanks to your great documentation I got a stable version now. The working typedefs are in my repo. Maybe you have a use for the parser to check your documentation. If you skip all replacements I added it will fail horribly :)
Here are some further questions:
- I do not know if this is inteded, hence, some base classes have protected members which are exposed by their children -> That gives me an error. An example would be ScrollEnablement and Object. Object has a public destroy, ScrollEnablement sets it to protected. Is this intended?
- Another thing is with protected functions in namespaces (example: jQuery namespace). As you (normally) cannot inherit a namespace those functions could not be used from outside. Is this intended, too?
If someone uses these definitions I would be glad for some feedback. I hope I can adjust it so much to get reliable typedefs automatically from your api reference. Check for regular updates.
I've made a lot of fixes now (see linked change), but some issues still are open, mainly:
- decision between DomRef, DomNode, Element and HTMLElement (only the latter two are valid)
- usage of wrapper types: too common for a quick fix and there's some small possibility that the wrapper was chosen by intention
Thanks @apazureck 👍
Did you consider uploading these definitions to Definitely Typed
See contribution guide for details.
If you do so it would be possible to consume these artifacts easily via npm.
npm install @types/ui5
Actually, that was my plan, too :) We are currently using the declarations in our project and I am thinking of some ways to improve the declaration file converter. Sadly I do not have the time to do that right now, as it would need some more adjustments to the ts files to make them reflect the content of UI5 properly:
- The documentation does not always reflect the used method signatures in js (Mostly a problem with optional parameters). So the declarations are not always correct and need manual adjustment. But I think it would be better to either change these directly in the documentation or extend the converter with a further override to keep the declaration files always up to date with the UI5 repo.
- I also have a huge problem when using jquery, as there is a namespace called jQuery in UI5, which collides with the type declarations of jquery when you use the openui.d.ts and jquery.d.ts together in one project. I did not figure out how to resolve this issue so far. I hope as my typescript skills will grow during the next months I will be able to fix that: http://stackoverflow.com/questions/39615811/how-to-prevent-duplicate-identifier-issue-when-declaring-namespaces-in-typescrip?noredirect=1#comment66552442_39615811. Contribution would be very welcome, too, if someone knows a workaround for that.
- The next improvement would also be to introduce ES5 properties to the UI5 classes to get a neater TS Syntax. But this is a decision you would have to make as it impacts your source files, but it would also be a benefit to JS programmers. (microsoft/TypeScript#10969)
- I hope to figure something out to get rid of the extend methods, but I am not sure if that is possible at all. As I get it right now it is a mix of a constructor and inheritance, but to fully understand this my js knowledge is too little right now :( If someone would like to look into that issue I would be very thankful, too.
Example:
sap.ui.define([
"basenamespace/controller/BaseController",
], function (BaseController: sap.ui.core.mvc.Controller) {
"use strict";
return BaseController.extend("basenamespace.controller.App", { ...
would be written in ts like that:
namespace basenamespace.controller {
class App extends sap.ui.core.mvc.Controller
{ ... additional props and methods / overrides ... }
sap.ui.define("basenamespace/controller/BaseController", new App());
}
1_manual_coorections : if you encounter these small errors it is almost as much effort to make a pull request here on github as manually correct them in the definition file. Github has a very nice workflow for small edits
2_jquery see https://github.com/afrische/ui5.d.ts/blob/master/jquery.sap.d.ts
4_modules_vs_define these are two very different implementations of the same concept. Don't conflate them, please. Typescript almost uses the ES6 module system. ui5 has its own module system. I don't think this is a good place to spend effort right now.
Personally i did not upload my definitions to definitelyTyped because they don't meet the quality expectations a reasonable user should have of that repository. What's wrong with a git submodule?
Reg. 1: can you elaborate a bit more on that (examples)? Do you want to determine overloaded signatures out of the optional markers for params? That might indeed be hard. To be honest, we didn't know JSDoc's concept of API "variants" when we started the documentation, might have been a better choice.
Reg. 4: to get rid of .extend
you have to find an alternative for all its functionality:
-
inheritance - should match the class inheritance of TypeScript, ES2015 quite well
-
constructor - even that matches quite well, as shown in #1107 and its fairly simple babel plugin
-
runtime metadata - thats IMHO the tricky part. Not only do we create the class implementation behind the scene (could be done with eval or with a transpiler step - both things that we currently try to avoid), we also create a runtime representation for the metadata.
As long as you "only" want to achieve a "description" of UI5 controls in TypeScript, you might ignore that part. But anything going into the direction of using TypeScript as the real source format has to solve that topic (or simply take over the metadata property as a class property - as it has been done in the above post - BTW: at least when I looked last at it, the table plugin missed to reflect the static nature of metadata, but that should be an easy enhancement). A natural, more "modern" way to express runtime metadata might be to use Javascript annotations , sorry decorators, but we did not yet investigate this .
...
Hi @apazureck and all, I like the approach :
namespace basenamespace.controller {
class App extends sap.ui.core.mvc.Controller
{ ... additional props and methods / overrides ... }
sap.ui.define("basenamespace/controller/BaseController", new App());
}
but it definitely has some issues:
sap.ui.define'd classes are not discovered by intellisense without writing some other verbose information that adds up to the verbosity and maintenance cost of a project.
The problem is that we have two inheritance systems: one by Typescript and the UI5 one.
The latter doesn't pose well for compression and obfuscation, since closure.js or uglify.js, given a single batch of code, will rename JavaScript objects without touching the reference that are string enclosed.
I skimmed through UI5 inheritance code some time ago to see if I could get out with some defs automatically then I formed the opinion that the best would be to convert to TypeScript the whole UI5, making use of interfaces for writing and documenting using pure JS/TS class hierarchy for components.
It can be done, albeit it's not trivial given the size of the source.
I see only advantages in
- having a simpler and more type-controlled environment as a core language engine
- supported by modern advanced development tools with supreme code assistance like WebStorm or VSC
- having the option to transpile your cautiously crafted whole app in a single minified/obfuscated JS file with some level of code protection.
Until then I will go with a simple declare var sap:any;
, since in these three years I ended up learning UI5 components by heart :).
Just my 2 eurocents.
--R
@afrische:
1_manual_coorections: This is definetly the way to go. I will try to test this in the future. First step will be to use the files from the sdk instead of the webservice of hana.ondemand. Then the changes are more obvious.
2_jquery: Are you sure that would transpile correctly? The Transpiler will would produce JquerySap.log, for example, instead of jQuery.log, if I am not mistaken.
HOTFIX to this issue: you can get the jquery.d.ts and uncomment declare var jQuery: JQueryStatic; (at the bottom of the file). After that you can still use jquery using the $...
4_modules_vs_define: I agree on that. Hence, here is a snippet of mine of the controller example, which works just fine:
// SapUI Definition
sap.ui.define("", ["sap/ui/core/mvc/Controller"], function (Controller: sap.ui.core.mvc.Controller) {
"use strict";
return Controller.extend("sap.ui.demo.wt.controller.App");
});
// Typescript definition:
namespace sap.ui.demo.wt.controller {
export class App extends sap.ui.core.mvc.Controller {
onShowHello() {
// show a native JavaScript alert
alert("Hello World");
}
}
}
The class is defined in typescript and then can be used by sapui. But this just may be a coincidence and may not work at all with more complex classes. Furthermore, I do not know if the performance would suffer from that (at least when loading it would, I guess).
@codeworrior:
Reg. 1:
Do you want to determine overloaded signatures out of the optional markers for params? That might indeed be hard.
- It is, indeed :) There are some methods with multiple optional parameters. Just try to use my definitions without any adjustment. I had some issues so far, but maybe it was another error.
Take sap.ui.define for example:
Typescript Declaration:
function define(sModuleName: string, aDependencies: string[], vFactory: any, bExport?: boolean);
Usage in JS (Walkthrough - Step 5: Controllers):
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function (Controller) {
"use strict";
return Controller.extend("", {
});
});
So the first parameter sModuleName should be an optional parameter. If you set null on this sap.ui crashes. I just use an empty string right now.
Reg 4: see answer to @afrische above.
@RobertoMalatesta: See the answer above, the approach worked for me (only a simple test right now, but I will try it out on my app today.
I beg you to try out my declarations and help me improve them. If you wrote ts code then you could just add the declarations and remove your declare var sap: any and see, if you can still use it. (I hope at least :))
Hi @apazureck. I just finished integrating your definitions inside my last UI5 project (29'268 lines for the TypeScript part only) and I definitely have only good news.
I took this Saturday morning to try your definions so I git-commited before, packed the usual backups just in case of fire, plugged in your defs and started the journey to TypeLand.
Visual Studio Code (best editor/IDE/RAD ever) did its job, spitting out more than 1600 errors.
Then, as expected, 1505 of them were really easy to fix, since they were caused by the fact that I do not use sIds to create UI5 objects.
As we don't have parameter naming in Typescript, options were interpreted as the first param. This was easy to fix by adding an undefined as a first.
Things that had to be tuned by hand:
- onsapenter not exestant in sap.ui.core.element
- sap.ui.core.Element.getMetadata not existing
- sap.ui.core.ValueState.Warning cannot be converted to sapui.model.type.String
- sap.ui.commons.layout.AbsoluteLayout << deprecated since 1.38 so not found (?)
- Control had no extend method
- sap.ui.core.Popup.Dock: Popup does not seem to have the type Dock = string exported
- JSONModel constructor should have oData and bObserve optional
- JQuery should have extend function defined
- sap.m.splitapp.ToDetail should have optional parameters
- sap.ui.core.format.DateFormat.getDateInstance() not existant:
I added: public static getDateInstance(oFormatOptions?: any, oLocale?: sap.ui.core.Locale): DateFormat; - format(oDate: any, bUTC ?: boolean): string;bUTC should be optional
- important: .addStyleClass() demotes every popover, label etc to a Control.
I then had to introduce a namespace for a few *commons I still use and a few things missing:
namespace sap {
export namespace ui {
export namespace commons {
export declare var Image: any
export declare var TextView : any
export declare var Label : any
export declare var Menu : any
export declare var Button : any
export declare var MenuItem : any
export declare var MenuTextFieldItem : any
export declare var Panel : any
export declare var MenuButton : any
// sap.ui.layout.BlockLayoutCell
}
export namespace core {
// export declare var Element : any
}
}
export namespace m {
export declare var P13nConditionOperation : any
export declare var MenuTextFieldItem : any
}
}
The whole process of refactoring took me about three hours and after that the web application and the unit tests were all responsive and successful at first run.
While converting the the help of VSC was impressive and introducing the declarations helped me get a couple of minor things that slipped in when using untyped javascript.
That's all for now,
in the hope these few notes can be of help to you to improve the declarations and to all the folks that use UI5.
Roberto
Thank you for taking the time and trying it out. I am glad it is working that well :) The id parameters in the define method (and constructors, I guess) are marked mandatory. As @afrische suggested, I will make a fork and change it in the documentation.
One thing I could not project correctly in ts was the protected visibility of class members. Therefore, all is public, except private methods, which are not declared - and cannot be. Some classes change the visibility from protected to public, which leads to a ton of errors. Maybe this is not intended by the developer, I am not sure and will have to do some investigations on that topic.
I left out the getmetadata method, as i was trying to represent them by es6 properties. I did not need the so far (except when debugging), but if they play a major part I can put them back in.
My version is built for 1.40 exactly, therefore, deprecated methods and classes are not included. I think I will put a version range to the declaration file generator to be able to support multipe versions. This also explanes the declarations in your sap.commons namespace (e.g. sap.commons.button deprecated in 1.38)
And if somebody wants to use typescript classes, I have good news, too: We changed our code (only controllers so far) to ts classes and it works just great (see my post above for an example). Hence, be aware if someone uses it in plain js it can be a little bit confusing, as ts generates the whole functions for namespaces. But a great benefit is the code completion using this and properties. Solved some issues we had (typos of properties).
Cheers
Hi @apazureck I'm just sponsoring your bindings on:
https://openui5.slack.com/messages/home/search/typescript/
but I want a percent.
--R
Some news on the typescript front:
Upcoming usage changes
If someone is using the definitions so far, the usage may change in future. I have problems running
import namespace jmodel = sap.ui.model.json.JSONmodel;
alongside module imports, which are looking something like this:
import * as enumerable from 'linq-es5';
Furthermore, I would like to extend them to play along with the bower packages you support, so I don't know how this will influence the ts definitions.
BUT this will be minor changes to the code (adding some imports maybe at the beginning of the file).
VSCode Plug-In
Furthermore, I am currently developing a vscode plugin, as @RobertoMalatesta was impressed by it - as am I right now. Check it out on my github repo, if you like: https://github.com/apazureck/openui5vscodeTypescriptTools
It contains a schema for the manifest.json and supports navigation from view to controller - and vice versa in simple openui5 projects (only 1 manifest, 1 controller per view). It should work with js, too. You can use it by copying it to your $USERFOLDER/.vscode/extensions. Better stuff is coming as my ui5 projects will get more complex and I am more experienced on this side.
Plus adding some snippets to generate classes and maybe later support for code completion on loosely coupled things like models.
Feedback and contribution very welcome!
Generator migration to TS/JS
I am planning to migrate the generator from C#/.NET to typescript/javascript and provide it as UI5 application. This may be (much) slower, but it will run anywhere and I guess you do not have to generate 10 ts declaration files per second.
The generator will also be included in the vscode extension, as long there are no official .d.ts on dt or tsd.
Contribution very welcome on that, too!
For JS Users
VS Code supports intellisense via typescript definitions. So this may be interesting for js programmers, too. If the definitions may be some day on a typescript server, js usage will improve as well without any additional work on the developers side.
https://code.visualstudio.com/updates#_better-javascript-intellisense
I hope this will get some more devs intrested in improving this topic, too. I don't know how good code completion and documentation integration is in the sap web ide, so this may be not of much interest for sapui5 users and js programmers at all, but my team and me really had a great benefit and experience getting started exploring the framework using ts.
@apazureck good stuff indeed.
The problem is with definitions and having to support UI5 inheritance mechanism.
YMMV but I got good results with declaring my own limited set TS objects, inside a custom namespace that can be seen as pure TS by the rest of the app while they use one of more UI5 components inside them to implement their functionalities.
I will try your plugin for sure, but not extensively since in a near future I will probably migrate my UI5 applications to something different and more TS friendly).
--R
@RobertoMalatesta: That's what the plugin should be for. So far I just had to code controllers and, therefore, no complex inheritance was needed. I wanted to write commands to add properties and events, as they have to be generated by the custom inheritance mechanism, as I see it. With that you can use the classes ecma2015 conform, too.
And maybe it is possible to add a pre-compile-step to the transpiling process, then ui5 can be used with full ts support and without any additional knowledge of the framework (and maybe better js output, too). Or you can check on file save and always append the extend part to the ts file.
Imo manually writing declarations or classes is no option (if you want to publish the declarations), as you would always have the work to adjust your code - and I'm too lazy for that ;) - besides all the bugfixing.
@apazureck Since it seems that this argument does not interest many more persons than the two of us, (not even the SAP UI5 team, since this issue has been closed long time ago) we could switch our discussion on this group:
https://openui5.slack.com/messages/home/search/typescript/
--R
We could, if I were in the openui5 slack group :) If you want you can add me (emai is in my profile)
@apazureck just asked one of the moderators how to add you. 🍻
Some more news on the typescript front:
I finally released my first preview of the typescript tools for UI5.
I hope it is ok to use the ui5 logo, if not please tell me and I'll remove it. I plan to update it during the next few weeks and try to keep the definitions up-to-date until I ported the ts definition generator to typescript.
Upcoming (planned) extensions:
- Generic events and models: For now using for example JSONModel does not return the type. I extended my JSON Model to have generic parameters, so getData() will be typed, as well as setData. The same is for events. The disadvantage would be, that you cannot port your js apps as easily, as
- Enumerations for getParameter: For events it is possible to get parameters by name. This could also be generated, as typescript allows string literals
- Improved code generation: Integrate protected methods/properties (they are public now), better overloading/optional parameters handling, so you do not have to adjust some methods manually to get them to work.
- Definitely typed: VSCode uses typescript declarations to support code completion and linting for javascript, too. But to do so, the definitions have to be on a public ts repository. If the definitions are in a state of running 'out of the box' I would like to publish them there, if it is ok to you.
@codeworrior: What tool do you use to generate the jsdoc json output? I would rather like to adjust the documentation in favor of always doing post processing to get the right defnintions.
As always, if somebody is interested in joining this (noble?) task, I would be glad to have some company.
Hi guys @apazureck @RobertoMalatesta @afrische , what is currently the recommended way / source to get typescript definitions for ui5? I tried out the definitions from @apazureck but they are missing the sap.ui.base namespace. There are also some definitions published on @types/openui5 but I wanted to extend / fix some of them via declaration merging which was a bit difficult due to the way it exposes certain objects.
I btw developed a sort of monkey patch to be able to use ES6 or typescriipt module syntax to import UI5 modules (without the need for an additional babel transpiler).
-
load this ui5 module first : https://gist.github.com/geekflyer/ab0b98a0fd788496a69e9e35cb6d851a
-
set "module" in compilerOptions to "amd"
Import modules like this:
import * as jQuery from 'jquery.sap.global';
import Control = require('sap/ui/core/Control');
import ParseException = require('sap/ui/model/ParseException');
import ValidateException = require('sap/ui/model/ValidateException');
import * as utils from './utils';
export modules like this:
export = {stuffToExport: 'woohoo'}
or
export const myNamedExport = 'foo';
export const myOtherNamedExport = 'bar'
I know the AMD shim is kind of hacky since it overrides / monkey patches sap.ui.define and also aliases it to define
but for now it seems to work for me. If it doesn't work on the long term I might plugin babel as post processor, but for now i wanted to try a more lightweight solution.
@geekflyer I use compile TS to ES6 and babel (https://github.com/MagicCube/babel-plugin-ui5)
but it's hack :(
@nardin Yeah I'm aware of the plugin, but I wanted to try a more lightweight solution for the moment. I have used ts -> babel -> ES5 in node.js in the past and it was a bit painful to set up build chain an ensure I can run tests, source-maps are correct etc, so that's why I wanted to give pure TS transpiler a shot for now.
Anyways - I'd be curious about your experience with the babel ui5 plugin together with UI5? One thing I didn't like about the transpiler plugin is that he would compile all classes to UI5 classes (.extend). I think it'd be nicer if one can opt in to making it a UI5 class by using a decorator or similar (@UI5) . I think it would be possible to implement that in the plugin, but don't have time for it now haha.
And which type definitions do you use?
@geekflyer: The sap.ui.base namespace is in the file sap.ui.d.ts. It is all ambient for now. I tried to change them to a modular synthax, but it didn't work, as the files did not get loaded anymore. Until then I had not time to check it again.
I am not sure about ES6, but I would also prefer it to use async await
. We have to take IE11 into account and the TS transpiler does not put out the classes as nested functions, but has a class object. I am not sure, if this works with the inheritance syntax of UI5.
Your way sounds really great, I did not research much on the amd topic, but it seems really useful to me now. My way for importing is to use sap.ui.define ...
and the synthax from my post on october 13th 2016. I also wanted to extend the vscode plugin to lint and add the missing files on require, so you just have to write import Control = sap.ui.core.Control and after that you get an alert that it is not added to the sap.ui.define array. After that you can code action the missing part automatically. But if there is a better way to do that for now I am all ears.
I was also thinking about extending the ts transpiler via its api to be able to write native typescript code and transpile it into the ui5 syntax. But as I read on their repo it is in a very early and experimental state, so I would wait a few months until it is grown a bit.
@apazureck Alright, after reading your post in detail again I figured the actual type definitions generated by you are probably those: https://github.com/apazureck/ui5.d.ts/tree/master/UI5Application1/UI5Application1/Scripts/typings/ui5 and the ones in the root directory of the repo are just the ones forked from @afrische , right? I guess it would be good to clean this up a bit :-D to avoid confusion haha.
As for exporting the definitions as modules I created the following ambient module definition and included it in my tsconfig.json
ui5.d.ts
declare namespace sap.ui {
function define(deps: string[], vFactory: Function, exposeToGlobal: boolean);
}
declare namespace sap.ui.core.Component {
export function getOwnerComponentFor(managedObject: sap.ui.base.ManagedObject): sap.ui.core.UIComponent;
}
declare module 'sap/ui/model/ParseException' {
export = sap.ui.model.ParseException;
}
declare module 'sap/ui/model/ValidateException' {
export = sap.ui.model.ValidateException;
}
declare module 'sap/ui/core/Control' {
export = sap.ui.core.Control;
}
declare module 'jquery.sap.global' {
export = jQuery;
}
The important part are those "declare module" things which basically re-export the global typedefs under particular module name. So when I import sap/ui/core/Control
etc. anywhere in my project using import Control = require('sap/ui/core/Control')
the result Control symbol will already have the correct type etc. . Unfortunately currently I have to create a re-export for every UI5 module that I'm using but perhaps it would be possible to generate those re-exports.
Your pointer to typescript's compiler API is interesting - I didn't even know they have something like that but did some research and it seems it's providing something similar to babel (although more immature).
As for my AMDShim I think a critical part (that might cause problems when dynamically loading ACTUAL amd modules in your application) is that I'm aliasing define = sap.ui.define
because the typescript compiler emits define
only. But maybe using the compiler API it would be possible to emit sap.ui.define
instead. Since this is a very simple transform it should be no rocket science to create a typescript plugin which applies this transform. Anyways, once I encounter the first "problem" with this aliasing I might spend some time on a transpiler plugin but for now I'm good.
Last but not least regarding ES6 and async await: . When you use typescript 2.1.0 or higher you can just set the target to "ES5" in the transpiler options and it'll transpile async await to it's ES5 equivalent. Before 2.1.0 that was only working when targeting ES6.
@geekflyer: Ok, I did not know the ES5 async await was integrated for ES5 in the new ts version. Thanks a lot for that information!
I know, shame on me, my account is pretty messy :) To be honest I did not want anyone to get the declarations from there, but to integrate the generator in my vscode plugin, so you can - more or less like in npm - the ts definitions you want. I will upload the definitions I am currently working with (derived from 1.42.6) this evening.
For example: I changed the defnitions for the JSON model to have generic parameters. There is, as far as I know, no possibility to typedef/alias possibility that supports generic parameters. So it would be an option to generate the definitions for users who move from js to typescript, so they do not have to change their code. Someone who starts from scratch could use the much more convenient generic model to have typed getData / setData.
OK, I do not really know anything about how AMD modules play along with UI5. I guess the simpler way (for now) is to have an ambient namespace and use the sap require and define methods at the top of a class.
If you want to change the declares to modules I guess you just could rename all namespaces to modules. Maybe the TS compiler allows nested module declaration and resolves them. And maybe browserify and gulp can do the trick and you can work around the sap module loading system, or it somehow works around that. I did not have the time to get into this so far.
@apazureck One of the reasons why i strongly prefer the ES6 module syntax (or commonjs) is that your local symbol lines up with the import path. In the AMD and sap.ui.define syntax the import paths and the symbol are defined on different lines in your file. This makes it harder to:
- identify unused imports (your IDE won't tell you)
- remove imports (temporarily or permanent) because you have to touch 2 places and be careful about that (instead of just deleting one line as in ES6 syntax)
- reorder imports.
But the other, even more important difference is that ES6 syntax is well understood by typescript and IDE's, which makes your IDE and typescript much much smarter. It will give you cross file code completion, better cross-file type inference and much better refactoring support. You also get completions for relative file names when writing out the imports etc. In webstorm it even supports auto-import of other modules similar like in Java. You'll lose all those advantages of typescript if you use AMD like module syntax ;-)
Ah ok, thank you for the explaination. That makes it much clearer. I currently use ES5 commonjs AND ambient namespacing. We have to support IE11 and I am not sure if even ES5 is too much for that old wreck.
I am not sure what the general output of the transpiler currently is, as I am not working with js anymore, but I tried to get it to have the import synthax like that:
import { Button } from 'sap.m';
this should resolve in sth. like
var sapm_1 = require('sap.m')
var test = sapm_1.Button ... etc.
But this lead to missing files in the frontend, so I came back to the sap.ui.define
way. Plus if you like to support inheritance you have to use the extend method, etc., so you cannot write plain typescript anyway.
I will play around a little with that. The goal would be to get the plugin to work with the bower packages provided by SAP and if I can get the transpiler to work with AMD, maybe that would improve the whole thing. Together with the bower packages and some gulping it may be a good way.
I used webstorm at the beginning, but I didn't want to spend money on a solution that did not fit well and so I ended up with vscode. Now that I implemented a simple xml linter and code completion I am not really missing anything (also the debugging is much better, the jetbrains chrome plugin crashed all the time...).
What I can do in the near future in VSCode
My first approach in the next weeks would be to realize something like that in the vscode extension, as it often happens to me that I import something and do not have it in the define array:
// 1. Define with sap synthax
sap.ui.define([
'sap/ui/core/mvc/Controller'
, 'sap/ui/model/Filter' // Warning: unused diagnose + CodeAction to remove
, 'sap/ui/model/Sorter' // Warning: unused diagnose + CodeAction to remove
, 'sap/ui/model/json/JSONModel' // Warning: unused diagnose + CodeAction to remove
, 'sap/ui/model/FilterOperator' // Warning: unused diagnose + CodeAction to remove
], function (ctrl){ // Warning: Not the same name as import Controller = ...
"use strict";
return ctrl.extend("my.project.controller.MyCtrl"); // Error: Not the same as class name
});
// 2. Create class to get completion and inherited members
namespace my.project.controller {
import Controller = sap.ui.core.mvc.Controller;
import Button = sap.m.Button; // Not imported diagnose + CodeAction to add
class MyController extends Controller {
...
}
// 3. Add the missing constructor and metadata etc. to the prototype of the generated class
After you perform the corrections:
// 1. Define with sap syntax
sap.ui.define([
'sap/ui/core/mvc/Controller',
'sap/m/Button'
], function (Controller, Button){
"use strict";
return Controller.extend("my.project.controller.MyController");
});
// 2. Create class to get completion and inherited members
namespace my.project.controller {
import Controller = sap.ui.core.mvc.Controller;
import Button = sap.m.Button;
class MyController extends Controller {
...
}
// 3. Add the missing constructor and metadata etc. to the prototype of the generated class
So at least you can check that for VSCode:
- identify unused imports
- remove imports (temporarily or permanent) because you have to touch 2 places and be careful about that (instead of just deleting one line as in ES6 syntax)
- reorder imports.
- refactoring support
So with some snippets and some extra linting it will be not a big problem to create custom controllers and controls. Disadvantages may be to have to respect a certain layout for documents and you are bound to vscode as IDE.
Perfect way
The perfect way would be to transpile typescript classes to the javascript syntax of UI5:
import { Button, Table } from 'sap/m'
import { Controller } from 'sap/ui/core/mvc'
export namespace my.app {
class MyController extends Controller {
}
// ... and so on
transpiles to
sap.ui.define(["sap/m/Button", "sap/m/Table", "sap/ui/core/mvc/Controller"], (Button, Table, Controller) => {
... // extend, props, metadata in UI5 style
}
But I am not sure if or how this is realizable. And you would have to think about source maps, and that ES5 properties do not resolve in the UI5 property style + metadata and the other stuff...
So I'll wait and see what the typescript compiler will grow into and maybe there will be a way to extend the compiler to do that.
I also don't think UI5 will come closer to the ES6 standard, especially in the inheritance system, as it would kill most of compatibility to older code. Hence, support of ES5 properties would be nice.
Hi @apazureck,
with regards to the inheritance concept gaps between UI5 and ES6 I just created a small experiment which works actually pretty nice so far.
Basically I'm using ES7+ decorators to decorate a ES6 class as "UI5Class". The decorator then modifies at runtime the constructor of the class - actually behind the scenes it'll just construct a ui5 class descriptor object and then call the .extend method of the parent method with the class descriptor.
Probably easier to understand in code. So here's my example (copied and pasted from my project):
decorators.ts (reuse file)
export function UI5Class(namespace) {
return function (originalConstructor) {
const parentUi5Class = originalConstructor.prototype.constructor;
const ui5ClassDescriptor = Object.assign({metadata: originalConstructor.metadata}, originalConstructor.prototype);
return parentUi5Class.extend(namespace + '.' + originalConstructor.name, ui5ClassDescriptor);
}
}
Stuff.ts (example class)
import ManagedObject = require('sap/ui/base/ManagedObject');
import {UI5Class} from './decorators';
@UI5Class('sap.pdms.ui')
export default class Stuff extends ManagedObject {
static metadata = {
properties: {
foo: {
type: 'string'
}
}
};
myMethod(){
return 'hello world';
}
};
and a small test (the test file is currently plain ES5) which checks that the metadata generated setters, manually defined methods etc. are there:
test.js
sap.ui.define([
'sap.pdms.ui.Stuff'
], function (Stuff) {
describe('testing ui5 class extension via decorators', function () {
it.only('getter defined via ui5 metadata exists, and manually defined method too', function () {
var stuff = new Stuff({});
stuff.setFoo('bar');
expect(stuff.getFoo()).to.equal('bar');
expect(stuff.myMethod()).to.equal('hello world');
})
});
}
);
As compared to the the babel plugin https://github.com/MagicCube/babel-plugin-ui5 the decorator approach makes the modifications at runtime instead of compile time.
One advantage of this approach is that you don't need an additional transpiler (or transpiler plugin), so it's simpler to maintain and setup.
However the bigger advantage and difference to the existing babel plugin is that with the decorator I can opt-in on a case-by-case base to the UI5 inheritance system and not use it automatically everywhere in my project. For non-ui5 helper classes I don't always wanna use it - or imagine you use some third party library whose ES6 classes you wanna extend.
I should probably create a repo for all the ES6 / Typescript related helpers (incl. the decorator) I'm developing 😄 .
@geekflyer: That sounds really promising!
I have to have another look at the output of the Gulpclass package, which also uses decorators to produce gulp tasks. And Angular2 also heavily relies on decorators. Maybe you even be able have an xml view template as decorator element, like in A2?
If you can get it to work for props and accesors, too, you could write the class completely in TS syntayx:
@UI5Class()
class MyClass {
@UI5Property()
foo: string
@UI5Property("float", {default: -5.0})
bar: number
@UI5Event()
// Not sure what to do here...
}
It even seems to fully play along with ES5, according to the typescript documentation.
One disadvantage I see would be a performance loss, as each Object has to get wrapped, if I understood you right.
Possible extension TS Declarations
And maybe I could adjust the generator to provide the decorators, too. So you could use the whole framework that way. That would be awesome! But I don't know if it is possible to use in declaration files and if the properties are getting called that way, too.
This does at least not give any compiler errors:
declare module test {
@UI5Class('my.test.class')
class A {
}
}
export function UI5Class(namespace) {
return function (originalConstructor) {
const parentUi5Class = originalConstructor.prototype.constructor;
const ui5ClassDescriptor = Object.assign({metadata: originalConstructor.metadata}, originalConstructor.prototype);
return parentUi5Class.extend(namespace + '.' + originalConstructor.name, ui5ClassDescriptor);
}
}
Another thought on your code:
Maybe you would be even able to rewrite the existing declarations to a modular syntax, you could use this way:
{ManagedObject} from 'sap/ui/base/ManagedObject';
which should resolve in
var ManagedObject_1 = require('sap/ui/base/ManagedObject');
That would be closer to the "standard" I know, at least, but it's not that much better. Are you getting intellisense for the managed object this way?
FYI:
Here is a project template using
- bower
- typescript
- browser-sync
It is a vscode project template, but it uses gulp watch, so it should work with other IDEs.
It takes a while to start, as the resources have to be copied from bower to the out folder, but after that it is as fast as nodemon/bs is. Should also work for js files (change the source pattern to include .js files, or just to copy all (**/*).
Hey,
is there any further attention on this? I'm really interested in using Typescript for SAPUI5. My Problem is that this non-official tools and hacky methods are no way in business software development. Any official toolset for this?
regards
Hey,
Using it in business development with great success (as does @RobertoMalatesta, I guess). You do not need any hacks and you can use everything like god (or SAP) intended. Typescript will just help your devs getting better coding experience and less testing involved, as strong typing helps over a lot of issues plain old js has working in a team.
If you want official tooling, then use the official toolchain, everything else will be "hacky".
If you might not want to use the official software I recommend checking out visual studio code. As there are typescript declarations for UI5 definitly typed which will provide extended intellisense experience even for javascript users.
I just can tell you that generic events and json models saved us a lot of guessing, or sometimes communication, and, thus, time in development. I don't know if the offical tools will help you with that, but maybe some SAP guys can answer that question. Furthermore, I got browser-sync to work and automated all my deployment with gulp. I am not sure if the SAP software can help you on that.
And if you feel even more adventurous, feel free to fork my extension for vscode and improve it with stuff you might need for your business development. I am very happy about any support I can get.
Cheers
@sebi5000 @apazureck
Sometimes a picture is worth more than thousands of words.
sigh...
OK, maybe @RobertoMalatesta is not using it with great success :)
Another question:
Do you plan to change the inheritance / class system any time soon in the future? Because I thought of using the TS compiler API to match the typescript import and inheritance system with require()/define() so I can skip the workarounds and do not have performance issues decorators might have.
OK, maybe @RobertoMalatesta is not using it with great success :)
400k UI5-specific TS lines and counting.
Starting using it from the beginning, 8 financial apps (each of them with some 100th screens & dialogs), ahem.
I only care about UI5 dev't.
And I imposed myself to never lie.
--R
@apazureck @RobertoMalatesta I will give it a try ;) I'm new to Typescript but know the principle. Comming from C# Edge many features are known. And it looks really nice and the benefits are huge. I can understand that SAP is 3-5 years behind the up-to-date development tools, because business isn't that fast but I can't understand why they prefer Javascript for Business Development. It's originally designed to make some fancy animations or effects in the Web Browser...
I am also coming from C# and I can tell you gonna like typescript. The nice touch is if you have WPF experience many things in openUI5 will be familiar (xml, databinding, etc.). And If you do not develop many custom controls, then you will not have any issues using hacky workarounds. I had no need to create custom controls so far, as we always found a solution built in openUI5. But we are working the way to make a compromise between the crazy things our design team wants and what openUI5 provides (who wants a GUI anyway?!).
I have to admit I like Typescript even more right now, as you can do some cool stuff due to js allowing very much. so you have advantages from both, a strongly typed system like in C# and a very flexible typesystem in js.
And oData is great btw. (at least if you have ASP.NET + EntityFramework Backend), don't let anyone tell you otherwise ;). I have written a Proxy and Interface generator and its just great when our backend gets updated I just can check if my classes will still work that way. And the auto paging of some controls, like the Table is pretty neat.
I am using typescript+sapui5 with ES2015 imports. I create a decorator (to handle inheritance in the ui5 way, calling a static extend method on base class) and I create a define function that translates the TypeScript AMD generated define() call into a sap.ui.define call.
Here is an example, intellisense is working fine with both sap.* namespace and my own classes:
https://github.com/lmcarreiro/ui5-typescript-example
I create a NPM package to make it reusable: https://www.npmjs.com/package/ui5ts
Hi @lmcarreiro,
That is really great! I have a half-finished generator for modular typescript definitions (no namespaces) with some extra spice, like templated events and models. I wanted to use the typescript compiler api to modify the ast, but it is quite instable, so I skipped this idea. What a great approach of yours. I hope I have some time the next weeks to give it a shot, but I will tell my colleague, maybe he can try it.
cheers!
@apazureck The bottleneck are the UI5 definitions, when you start writing core using TypeScript you end up finding a lot of differences between UI5 API documentation and the TS definition files.
Actually I've written a couple of decorators for using ui5 in typescript too. Feel free to include them in your library @lmcarreiro . They also have some support for ui5 aggregations and properties by turning them into native javascript getters and setters and under the hood call the ui5 model.
export function UI5Class(namespace: string) {
return function (originalConstructor) {
const ui5ClassDescriptor: any = {
metadata: originalConstructor.metadata,
constructor: originalConstructor
};
// copy over static renderer property for controls
if (originalConstructor.renderer) ui5ClassDescriptor.renderer = originalConstructor.renderer;
/**
* Extract all prototype property descriptors and later assign them back to the ui5 generated to prototype (and don't pass them to the .extend class descriptor).
* The reason is basically that UI5 doesn't handle ES5 getters and setters and some other edge cases of special properties properly, when defining them on the .extend class descriptor.
* Side comment: Probably UI5 should rather copy over / analyze the *property descriptors* instead of the actual *properties* to avoid those problems.
*/
const staticPropDescriptors = Object.getOwnPropertyDescriptors(originalConstructor);
const prototypePropDescriptors = Object.getOwnPropertyDescriptors(originalConstructor.prototype);
const BaseClass = Object.getPrototypeOf(originalConstructor);
const ui5Constructor = BaseClass.extend(namespace + '.' + originalConstructor.name, ui5ClassDescriptor);
Object.defineProperties(ui5Constructor.prototype, prototypePropDescriptors);
Object.entries(staticPropDescriptors).forEach(([key, descriptor]) => {
if (typeof ui5Constructor[key] === 'undefined') Object.defineProperty(ui5Constructor, key, descriptor);
});
return ui5Constructor;
}
}
export interface IPropertyOptions {
type: 'string'|'boolean'|'int'|'float'|'object'|'any'|'string[]'|'boolean[]'|'int[]'|'float[]'|'object[]'|'any[]'|string;
group?: 'Accessibility'| 'Appearance'| 'Behavior'| 'Data'| 'Designtime'| 'Dimension'| 'Identification'| 'Misc'
defaultValue?: any;
bindable?: true|'bindable';
}
const defaultPropertyOptions : IPropertyOptions = {
type: 'any'
};
export function UI5Property(options?: IPropertyOptions) {
options = Object.assign({}, defaultPropertyOptions, options);
return function (prototype, propertyName) {
const constructor = prototype.constructor;
constructor.metadata = constructor.metadata || {};
constructor.metadata.properties = constructor.metadata.properties || {};
constructor.metadata.properties[propertyName] = options;
Object.defineProperty(prototype, propertyName, {
get(){
return this.getProperty(propertyName);
},
set(value){
this.setProperty(propertyName, value)
}
});
}
}
const aggregationDefaultOptions = {
multiple: false,
visibility: 'public'
};
export interface IAggregationOptions {
type?: string;
multiple?: boolean;
singularName?: string;
visibility?: 'public'|'hidden';
bindable?: true|'bindable';
}
export function UI5Aggregation(options?: IAggregationOptions) {
options = Object.assign({}, aggregationDefaultOptions, options);
return function(prototype, aggregationName) {
const constructor = prototype.constructor;
constructor.metadata = constructor.metadata || {};
constructor.metadata.aggregations = constructor.metadata.aggregations || {};
constructor.metadata.aggregations[aggregationName] = options;
Object.defineProperty(prototype, aggregationName, {
get(){
return this.getAggregation(aggregationName);
},
set(value){
this.setAggregation(aggregationName, value)
}
});
}
}
here's a small usage example:
// ... imports of Controls etc. above
@UI5Class('my.ui5.controls')
export default class MyControlWithBusyIndicator extends Control {
@UI5Aggregation({visibility: 'hidden'});
busyIndicator = new FlexBox({
fitContainer: true,
height: '16em',
alignItems: 'Center',
justifyContent: 'Center',
alignContent: 'Center',
items: new BusyIndicator({text: '{i18n>busy_text'})
});
@UI5Property()
isBusy = true;
@UI5Aggregation()
content: Control;
static renderer = (rm, oControl: MyControlWithBusyIndicator) => {
rm.write('<div');
rm.writeControlData(oControl);
rm.write('>');
if (oControl.isBusy) {
rm.write('<div> Loading... </div>');
} else {
rm.renderControl(oControl.content);
}
rm.write('</div>');
}
}
const myControl: MyControlWithBusyIndicator = /* getting a reference from the control from somewhere */;
myControl.isBusy = false; // sets the ui5 property, triggers rerendering etc. - no need to call myControl.setProperty('isBusy', true) or anything like that. (even though this is exactly what will be called under the hood)
@lmcarreiro, I just used controllers so far and did not do any custom components, so it worked pretty well most of the time.
@lmcarreiro @geekflyer maybe we could think of a repo to work on that topics together. I could provide the definition parser, a project template with bsync and my extension for vscode with naviation and autocomplete. I would like to merge this together to get better, simpler and more stable code.
I'll see what I can do on the parser the next weeks.
@apazureck I'm not actively working on ui5 anymore (my stack is nowadays ts + react + mobx) but feel free to use whatever code I've posted above and put it into your repo. Btw I'm also looking for a maintainer for https://github.com/geekflyer/openui5-mobx-model which works nicely together with typescript ^^.
@geekflyer, I started working with ui5 three weeks ago, but as soon as I understand your decorators better, I will certainly put them into my npm package and deprecate my own. It was a good idea of yours to put just the namespace in the UI5Class decorator parameter and get the name of the class from the originalConstructor, this way you don't have to write this name two times, like in my UI5 decorator.
@apazureck, It's a good idea, I don't know if I will have the time needed to contribute, but we can try. In my example https://github.com/lmcarreiro/ui5-typescript-example I got some errors because the differences between @types/openui5 definitions and the API. I'll try with your's and help fix things if I found something different than the API docs.
+1
Is there any chance that somebody (@apazureck?) updates openui5 definitions at definitelytyped?
@emumanu I recently published some openui5 types to npm. The module name is openui5-types
and the project is at https://github.com/r-murphy/openui5-types. Please open issues for and incorrect types or enhancements.
The problem with the typings is that the UI5 Framework does not really play along with ES and, thus, typescript. The inheritance system would need a custom typescript compiler flavor. I started have a look at the typescript compiler api, but it did not lead anywhere.
@lmcarreiro did a great job on writing a decorator and the define function to use the ts compiler with amd. I think personally it is the best approach to UI5 with typescript so far. I wrote typings generator, which plays along with that decorators.
Sadly, as I see, @r-murphy did write a parser, too. I don't know how far you are for now, but you can have a look at my declaration parser it at the development branch. I contacted @lmcarreiro to get the typings up and running with his plug-in, but it did not work out so far. And I did not have the time to have a closer look at it. It would be nice if we could work to gether on that, so there are not ten parsers and typings out there.
My Parser:
Also almost everything is configurable via a config.json:
- You can manipulate the api.jsons with jsonpath and javascripts
- You can fix wrong types and parameter names
- You can destinguish between global modules and "normal" modules
- You can control the output with handlebars templates.
- You can postprocess all output files with globs and regex-replace
I did export default
module export so far, but I would like to move to export =
export style, as I think it closer reflects the UI5 modules. This together with the decorators and overridden define function would result in writing "native" typescript and getting almost native ui5 code, which would also be usable in javascript and be accessed like the native ui5 modules.
You can see the typings in action at https://github.com/apazureck/ui5-typescript-example. Maybe you can have a look at them and get them to work. @lmcarreiro did adjust his functions, but I did not get them to work so far, but did also not have that much time the last weeks :(
In the long run it would be nice if we could put our effort together and maybe we could turn @lmcarreiro 's or @r-murphy 's npm packages in some kind of ui5-cli to create the declarations and do other stuff (like controllers, classes, etc.). In my opinion it would be best to have one central place where typescript for UI5 happens.
EDIT: Just to be clear, I don't care which parser is used to get what typings, but I think there should be only one parser, which puts out the typings instead of maintaining different typings. Sadly I did not tell earlier that I was doing something so we did the same thing two times :( It would be great if we could work on one parser together and one npm package to provide typescript.
Thank you for the quick replies.
The reason I was asking is because I wanted to use a c# to javascript converter to work on OpenUI5. The c# assemblies for the converter are based on the typescript definitions at definitelytyped.
I hope you (@apazureck, @r-murphy and @lmcarreiro) could unify your efforts to get the best typescript possible for UI5, and if you can, please update the definitions at definitelytyped. That way, more people that don't know about this thread can also learn about your typescript effort on OpenUI5. For example, the guy who updated definitelytyped has another parser:
Maybe there's some useful ideas for you there.
BR
@apazureck Yes I agree that we should collaborate and try to consolidate. I'll reach out to you outside this thread. I like some of the approaches used in your generator. However as of now it doesn't work for my apps.
My generator is actually a fork of @lmcarreiro's so I didn't write it from scratch. I have a few enhancements planned, but as of now it generates types used in 5 production apps at my work, with more being converted and tested now. Prior to the generator my team was manually editing and using the types from definitelytyped, but we wanted to get a working generator as a more maintainable approach.
And for transforming the ES modules and classes into UI5's module and class system, I have a babel plugin for that, rather than using decorators. babel-plugin-transform-modules-ui5. This plugin also works with non-typescript ES classes and modules and actually pre-dates converting our apps to typescript.
And an example of both in action.
https://github.com/r-murphy/openui5-masterdetail-app-ts
@emumanu I've avoided definitelytyped so far since my generator is in the early stages. But I think you're right that we should aim to get something on there for easy discoverability.
@r-murphy: Sounds great, I am looking forward hearing from you.
I did not find the time lately to work on the parser. I don't think that will change until end of April. So if you have the time to go on feel free to take what you need.
But in my opinion we should discuss how the typings should look like, first. I hoped once the parser would be provided for example by @lmcarreiro's npm package the discussion about how the typings should look like would start. But I think it is better to fiure that out first, as there may be some breaking changes. I am talking about how to resolve imports and how you can do exports in your module so the ts compiler will put out good js in the first place.
I did not have a closer look at babel so far. But as I understand it transforms javascript to other javascript, so the mappings would not be correct anymore, do they? Does your plugin solve that problem? So it would only be for distribution purpose, I guess. Is that correct?
Linked to: Bridge-Forums
Bridge-C# to Javascript -> using Retyped to create Retyped.openui5
Hello everyone.
Please Checkout this mono-repo:
Specifically the @openui5/ts-types package.
- https://www.npmjs.com/package/@openui5/ts-types
- https://github.com/SAP/ui5-typescript/tree/master/packages/ts-types
Feedback & Contributions always welcome 😄
For the TypeScript fans in this thread, I would like to mention the typescript
branch in our recently published sample app:
https://github.com/SAP-samples/ui5-cap-event-app/tree/typescript
See the README over there for an explanation. Yesterday's UI5ers live session (recording will be available in a few days) has some coverage as well.
Hello @akudev.
Could you please link the session recording when available ?
@bd82 The recording is now available here: https://www.youtube.com/watch?v=0notj9PPTho
Let's re-open this issue to make it formally clear that there is progress and active work.
@akudev
Too little, too late.
A pity.
-- R
As TypeScript type definitions are being regularly released since 1.90, I close this as fixed.
In addition to the definitions, there are example applications in TypeScript, incl. custom controls, there is a control library in TypeScript, a watch tool helping with control development, and hints how the type definitions even can help when developing in JavaScript in previously existing applications.
Links to all these resources can be found at https://sap.github.io/ui5-typescript (which is going to be updated as new content is created). That repository is also the location for tracking issues and enhancing the definitions further.