Skip to content
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 definitions #88

Closed
romanov opened this issue Jul 8, 2014 · 80 comments
Closed

TypeScript definitions #88

romanov opened this issue Jul 8, 2014 · 80 comments

Comments

@romanov
Copy link

romanov commented Jul 8, 2014

Is there any plan to release definitions for TypeScript?

@romanov romanov changed the title TypeScript bindings TypeScript definitions Jul 8, 2014
@akudev
Copy link
Contributor

akudev commented Jul 10, 2014

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

@stephenfhunt
Copy link

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.

@klaus-liebler
Copy link

I am interested as well.

@RobertoMalatesta
Copy link

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

@afrische
Copy link
Contributor

@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);

@RobertoMalatesta
Copy link

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

@antanas-arvasevicius
Copy link

+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).

@derKosi
Copy link

derKosi commented May 27, 2016

+1

@julicjung
Copy link

+1 - would love to see .tsd files for OpenUI5!

@antanas-arvasevicius
Copy link

not only .tsd, but TSX/JSX could be used for declarative UI there is no need for custom XML UI schemas in 2016.

@cschuff
Copy link
Contributor

cschuff commented Jun 23, 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.

@samba2
Copy link

samba2 commented Jul 13, 2016

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

@qualiture
Copy link

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

@afrische
Copy link
Contributor

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

@apazureck
Copy link

apazureck commented Sep 12, 2016

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

@apazureck
Copy link

apazureck commented Sep 14, 2016

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

@codeworrior
Copy link
Member

codeworrior commented Sep 15, 2016

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 : any Blob ✔️
  • arraybuffer : any ArrayBuffer ✔️
  • date : any Date ✔️
  • event : any either jQuery.Event or sap.ui.base.Event ✔️
  • integer : number int (convention used by UI5) ✔️
  • sap.ui.base.ManageObject : sap.ui.base.ManagedObject ✔️
  • objec : any ✔️
  • oWindow : any Window ✔️
  • sting[] : string[] ✔️
  • sap.ui.model.analytics.odata4analytics.ParametrizationRequest : any sap.ui.model.analytics.odata4analytics.ParameterizationRequest ✔️
  • regexp : string_RegExp_ ✔️
  • element : any Element ✔️
  • 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 and null it is more difficult as we don't want to lose the information
  • DomNode, DOMNode, domRef, DomRef, DOMRef : any Element or HTMLElement, to be discussed

Unqualified References or Wrong Package (fix)

  • CalendarAppointment : any sap.ui.unified.CalendarAppointment ✔️
  • Control : sap.ui.Core.Control ✔️
  • EntityType : any sap.ui.model.analytics.odata4analytics.EntityType ✔️
  • InvisibleControl : any sap.ui.core.InvisibleText ✔️
  • MenuButton : any sap.m.MenuButton ✔️
  • ObjectNumber : number sap.m.ObjectNumber ✔️
  • sap.m.Control : sap.ui.core.Control ✔️
  • ScrollEnablement : sap.ui.core.delegate.ScrollEnablement ✔️
  • TablePersoController : any sap.m.TablePersoController ✔️
  • TablePersoDialog : any sap.m.TablePersoDialog ✔️
  • sap.ui.core.Controller : sap.ui.core.mvc.Controller ✔️
  • sap.ui.core.InvisibleControl : any sap.ui.core.InvisibleText ✔️

Visibility / Missing Documentation (should be fixed, but not necessarily as suggested)

  • sap.ui.base.ManagedObjectMetadata : any made public ✔️
  • sap.ui.suite.TaskCircleColor : any misplaced JSDoc doclet ✔️
  • sap.ui.demokit.UI5EntityCueCardStyle : any misplaced JSDoc doclet ✔️
  • sap.m.TabStripItem : any type 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 : any Object 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 : any this 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.

@antanas-arvasevicius
Copy link

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.

@apazureck
Copy link

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:

  1. 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?
  2. 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.

@codeworrior
Copy link
Member

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

@bd82
Copy link
Member

bd82 commented Sep 29, 2016

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

more details.

@apazureck
Copy link

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:

  1. 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.
  2. 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.
  3. 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. (Accessors on class declarations microsoft/TypeScript#10969)
  4. 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());
}

@afrische
Copy link
Contributor

afrische commented Sep 30, 2016

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?

@codeworrior
Copy link
Member

@apazureck:

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 ES6 Support in UI5 Project #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 .

...

@RobertoMalatesta
Copy link

RobertoMalatesta commented Sep 30, 2016

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

@apazureck
Copy link

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.

@RobertoMalatesta
Copy link

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

@sebi5000
Copy link

@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...

@apazureck
Copy link

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.

@lmcarreiro
Copy link

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

@apazureck
Copy link

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!

@antanas-arvasevicius
Copy link

antanas-arvasevicius commented Oct 9, 2017 via email

@lmcarreiro
Copy link

lmcarreiro commented Oct 9, 2017

@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.

@geekflyer
Copy link

geekflyer commented Oct 9, 2017

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)

@apazureck
Copy link

@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.

@geekflyer
Copy link

@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 ^^.

@lmcarreiro
Copy link

@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.

@HudsonAfonso
Copy link

+1

@emumanu
Copy link

emumanu commented Mar 31, 2018

Is there any chance that somebody (@apazureck?) updates openui5 definitions at definitelytyped?

@r-murphy
Copy link
Contributor

@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.

@apazureck
Copy link

apazureck commented Apr 1, 2018

Hi @r-murphy @emumanu,

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:

  1. You can manipulate the api.jsons with jsonpath and javascripts
  2. You can fix wrong types and parameter names
  3. You can destinguish between global modules and "normal" modules
  4. You can control the output with handlebars templates.
  5. 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.

@emumanu
Copy link

emumanu commented Apr 1, 2018

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:

Lukas May Parser

Maybe there's some useful ideas for you there.

BR

@r-murphy
Copy link
Contributor

r-murphy commented Apr 1, 2018

@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.

@apazureck
Copy link

@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?

@samuelGrahame
Copy link

samuelGrahame commented Apr 3, 2018

Linked to: Bridge-Forums
Bridge-C# to Javascript -> using Retyped to create Retyped.openui5

@bd82
Copy link
Member

bd82 commented Apr 27, 2019

Hello everyone.

Please Checkout this mono-repo:

Specifically the @openui5/ts-types package.

Feedback & Contributions always welcome 😄

@akudev
Copy link
Contributor

akudev commented Apr 9, 2021

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.

@bd82
Copy link
Member

bd82 commented Apr 11, 2021

Hello @akudev.
Could you please link the session recording when available ?

@akudev
Copy link
Contributor

akudev commented Jun 1, 2021

@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 akudev reopened this Jun 1, 2021
@RobertoMalatesta
Copy link

@akudev
Too little, too late.
A pity.
-- R

@akudev
Copy link
Contributor

akudev commented Dec 3, 2021

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.

@akudev akudev closed this as completed Dec 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests