npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ui5-class-extend

v1.1.0

Published

Type-safe way to write UI5 classes using modern JavaScript classes.

Downloads

5

Readme

UI5 Class Extend

API Reference

Type-safe way to write UI5 classes using modern JavaScript classes.

Installation

Use npm to install:

npm install ui5-class-extend

Please note that this library works with TypeScript v5.0 or higher and depends on the official ESM-style UI5 types @openui5/types or @sapui5/types which will not be automatically installed.

Furthermore, a code transformation is needed to transform UI5-style ESM imports into valid UI5 code, e.g. with Babel and either babel-plugin-ui5-esm or babel-plugin-transform-modules-ui5.

Why not use @ui5/ts-interface-generator?

The tool @ui5/ts-interface-generator works by generating TypeScript code that add the automatically generated method signatures by means of interface merging, adding an additional preprocessing step before compiling. Also a one-time manual step is required to fix the constructor signature.

In contrast, this library aims to provide the automatically generated method and constructor signatures directly at compile time without any additional steps.

Usage

Extending a Class

Use the ui5Extend decorator factory and Ui5Base to extend from an UI5 class:

import Control from "sap/ui/Control";
import { Ui5Base, ui5Extend } from "ui5-class-extend";

@ui5Extend()
class MyControl extends Ui5Base(Control) {
  init() {
    super.init();

    console.log("My Control!");
  }
}

const control = new MyControl("mycontrolid");
// My Control!

You can optionally pass a fully qualified UI5 name as argument to ui5Extend:

@ui5Extend("my.controls.MyControl")
class MyControl extends Ui5Base(Control) {
  // ...
}

If you're not able to use decorators, you can also use ui5Extend() as a function:

const MyControl = ui5Extend("my.controls.MyControl")(
  class MyControl extends Ui5Base(Control) {
    // ...
  }
);

Providing Metadata

You can define extra control metadata, such as properties or events as argument to Ui5Base. The method signatures for the UI5-generated methods based on the metdata will automatically be provided by TypeScript.

import Control from "sap/ui/Control";
import { Ui5Base, ui5Extend } from "ui5-class-extend";

@ui5Extend()
class MyControl extends Ui5Base(Control, {
  metadata: {
    properties: {
      text: {
        type: "string",
        defaultValue: "",
      },
    },
  },
}) {
  init() {
    super.init();

    console.log(`My Control with text '${this.getText()}'!`);
  }
}

const control = new MyControl("mycontrolid", {
  text: "Hello World!",
});
// My Control with text 'Hello World!'

Overriding Automatically Generated Methods

Due to a TypeScript limitation, to override automatically generated methods you need to use the property initialization syntax. Please note that arrow functions are not supported in this case, see also Caveats.

import Control from "sap/ui/Control";
import { Ui5Base, ui5Extend } from "ui5-class-extend";

@ui5Extend()
class MyControl extends Ui5Base(Control, {
  metadata: {
    properties: {
      text: {
        type: "string",
        defaultValue: "",
      },
    },
  },
}) {
  init() {
    super.init();

    console.log("My Control!");
  }

  setText = function (this: MyControl, value: string): MyControl {
    //    ^ Use property initialization syntax
    console.log(`Setting text '${value}'`);

    return this.setProperty("text", value);
  };
}

const control = new MyControl("mycontrolid", {
  text: "Hello World!",
});
// My Control!
// Setting text 'Hello World!'

To override methods from the base class, you can use the usual syntax.

Overriding Types

The type system of UI5 is very limited. You can overwrite any types with a more appropriate TypeScript type using the typed<T> function.

import Control from "sap/ui/Control";
import { Ui5Base, ui5Extend, typed } from "ui5-class-extend";

@ui5Extend()
class MyControl extends Ui5Base(Control, {
  metadata: {
    properties: {
      text: {
        //                                 v UI5 type
        type: typed<"hello" | "goodbye">()("string"),
        //          ^ TypeScript type   ^ Due to TypeScript limitation this
        //            as generic          unusual syntax is required
        defaultValue: "hello",
      },
    },
  },
}) {
  init() {
    super.init();

    console.log(this.getText());
  }
}

const control = new MyControl("mycontrolid", {
  text: "nice to meet you",
  //    ^ This will result in a type error since text can only be "hello"
  //      or "goodbye"
});

Providing a Renderer

You can use the Renderer interface to define your renderer. Then specify the renderer as argument to Ui5Base. Due to a TypeScript limitation, you need to cast your renderer into a generic renderer to prevent cyclic type references:

import Control from "sap/ui/Control";
import { Ui5Base, ui5Extend, Renderer } from "ui5-class-extend";

const MyControlRenderer: Renderer<MyControl> = {
  apiVersion: 2,

  render(rm, control) {
    // (rm: RenderManager, control: MyControl) => void
    // ...
  },
};

@ui5Extend()
class MyControl extends Ui5Base(Control, {
  metadata: {
    properties: {
      text: {
        type: "string",
        defaultValue: "",
      },
    },
  },
  renderer: MyControlRenderer as Renderer,
  //                          ^ This cast is necessary
}) {
  // ...
}

Caveats

  • Constructors are not supported

    If you specify a constructor, everything aside property initializations will be ignored. Instead you can use the init() method to perform initializations.

  • Accessing this during property initializations is not supported

    During property initializations this refers to a foreign object, therefore might result in unexpected behavior when accessed or modified. Instead you can use the init() method to perform initializations.

    When assigning a bound function to a property, the function body can refer to this again (see also Overriding Automatically Generated Methods). However, arrow functions are not supported.

  • Accessors and setters are not supported

    A TypeError will be thrown if you define accessors or setters in your class. You can define a getter/setter method instead.

  • Generated method signatures don't return this

    In UI5, a lot of setter methods return this to enable method chaining, however due to a TypeScript limitation, this library will generate methods that return void instead of this.

  • Generated method signatures lack JSDoc

    Even if you annotate the metadata object with JSDoc, the generated methods will not get annotated with the corresponding JSDoc.