question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Discussion] Support for control development with new "ts-types-esm" type definitions

See original GitHub issue

This is the place to discuss control development support with the new ES module version of the UI5 type definitions, the one recommended to be used going forward.

This is also a continuation of https://github.com/r-murphy/babel-plugin-transform-modules-ui5/pull/66, which turned off-topic for the location where it was discussed.

Problem

Accessor methods for the properties, aggregations etc. (functions like getMyProperty() and addMyAggregation() and attachSomeEvent()) are in general not explicitly written in the control code, but generated by UI5 at runtime. This means they are not known to TypeScript at development and build time.

But even the control’s own renderer will have to do things like

oRenderManager.text(oMyControlInstance.getAdditionalText());

As the getAdditionalText() getter for the “additionalText” property is not known to TypeScript, the method call will be marked as error. In addition, TypeScript also doesn’t know that new MyControl({additionalText: "hi"}) is valid, but new MyControl({thisDoesntExist: "hi"}) or new MyControl({additionalText: {someProp: 3}})is not.

So the control developers themselves, but also application developers using the control, will get TypeScript errors (and no code assist) for all accessor method calls and for the cosntructor settings object.

One could argue that defining the property getter manually is not a big deal, but once you think about application developers using a control developed by others, all potentially used methods need to be declared. For properties this is relatively simple (although e.g. things like bindXY()for bindable properties could be easily forgotten). But for one single aggregation, it’s already quite a list of methods that need to be declared correctly:

        // aggregation: content
        getContent(): Control[];
        addContent(content: Control): this;
        insertContent(content: Control, index: number): this;
        removeContent(content: number | string | Control): this;
        removeAllContent(): Control[];
        indexOfContent(content: Control): number;
        destroyContent(): this;
        bindContent(bindingInfo: AggregationBindingInfo): this;
        unbindContent(): this;

Solution

According to current thinking, the best solution is generating a TypeScript interface, which declares the missing methods and the constructor settings object type. This generation cannot happen in the TypeScript transpilation, but needs to happen in parallel to development: not only the build result needs to contain the additional interfaces, but even the sources - otherwise the solution does not work for the control developer.

While the interface content itself is straightforward, it is more tricky to make TypeScript recognize that it extends the developed control class. Generating the interface right into the control file would work, but was discarded as this can interfere with the manual coding that is happening in parallel. The currently planned solution makes use of TypeScript’s module augmentation and interface merging features to accomplish the enrichment from a stand-alone generated file next to the developed control file.

A generated file looks like this right now:

import { $ControlSettings } from "sap/ui/core/Control";

declare module "./MyControl" {
    /**
     * Interface defining the settings object used in constructor calls
     */
    interface $MyControlSettings extends $ControlSettings {
        text?: string;
    }

    interface MyControl {
        // property: text
        getText(): string;
        setText(text: string): this;
    }
}

Caveats

As interfaces cannot define constructors, the different constructor signatures still have to be defined within the original control class. But at least they don’t need to be changed after creation, as they are independent from the control API definition.

To make the interface merging work, the original control module needs to export the control class not only as default export (which is needed for regular usage of the control in the same way the standard controls of UI5 work), but also as named export in addition. This is a bit hacky, as discussed in https://github.com/r-murphy/babel-plugin-transform-modules-ui5/pull/66. An alternative might be to require an explicit import of the interfaces (more manual one-time effort; current proposal does not seem to work).

Discussion

This issue is meant to bundle discussions and feedback and pull them away from other places, where it would be off-topic. Suggestions how to work around the caveats, or alternative ideas are welcome!

The code generating the current version of the interfaces is right now not available on GitHub, but the plan is to offer it, once a home is found.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
akudevcommented, Dec 3, 2021

@stockbal Cool, thanks again! It’s indeed surprising that it makes a difference whether a class is exported immediately or separately, but anyway: it works. I’ll adapt the generator. If you have more good ideas, keep them coming! 😉

Regards Andreas

1reaction
akudevcommented, Nov 25, 2021

Hi @stockbal,

Ouch! Of course, that’s the solution! 😃 Sometimes you don’t see the forest due to all the trees…

Thanks a lot! Andreas

Read more comments on GitHub >

github_iconTop Results From Across the Web

Volume 2 - Controls Management - CISA
With management's support, processes are defined to identify, implement, and assess controls on an ongoing basis to ensure the resilience of services and...
Read more >
Section 1. Developing a Logic Model or Theory of Change
By whatever name you call it, a logic model supports the work of health promotion and community development by charting the course of...
Read more >
What is a decision support system (DSS)? - TechTarget
Learn how a decision support system (DSS) provides organizations with fast, organized and comprehensive information for making well-informed decisions.
Read more >
What are issue types? | Atlassian Support
Issue types distinguish different types of work in unique ways, and help you identify, categorize, and report on your team's work across your...
Read more >
The HTML5 input types - Learn web development | MDN
There are a few other control types that cannot be easily grouped together ... discussed in this article have wide support across browsers....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found