Want to know how we resolved it? Jump to How to resolve it?.
We'd like to have a base class with some methods and from that x sub-classes. The base class (as it is their common denominator) defines (& houses the definition) a
"interface" using JSDoc's @typedef
. The created string literal is then used inside the sub-classes Interfaces
metadata declaration (marker/tag interface).
This gives us the possibility for runtime comparisons like getMetadata().isA("InterfaceStringHere")
and we can make use of the InterfaceLinter.
We then want to make use of the native .getInterface()
method which gives us the public API of an object/class and typecast it to what we know at design-time
which is the Interface itself or in this particular case we want to type-merge as we definitely know whatever will be passed will have it's base from
sap.ui.base.Object
+ SomeInterface
. Thus giving us code-completion using this class then.
Upon creating this example I realized that the code-completion seems to be better when you're inside a controller, instead of a custom class/object. This might be part of the problem?
When you comment out the code in the onInit
of the MainView.controller.js
you get full code completion for all 3 types that're merged there. If you
try to do the same within ConsumingClass
it won't work.
I had issues recreating it in my own VSC (non-company computer which has X extensions)... there everything worked well in a freshly created project. I then took this project and put it into a recently created BAS Dev Space which is running [email protected] for intellisense and there I could recreate it when comparing it to [email protected].
But again, maybe I need more than just a jsconfig like:
Upon creating this example I realized that the code-completion seems to be better when you're inside a controller, instead of a custom class/object. This might be part of the problem?
The only one that matters is iljapostnovs.ui5plugin
as it also gives some code-completion. Other than that only prettifier.
Might not be the perfect usage of JSDoc or most appropriate but it worked quite well for code completion on pure JS projects so far. The ConsumingClass
isn't used anywhere
as it is just for demo purposes regarding code completion. The setup/starting of the app was also not considered at all in this demo.
In all examples I've continously used the "Restart TS Server" functionality to make the tests as reliable as I could (incl. complete reload of the window sometimes).
Same jsconfig.json
in both variants:
{
"include": [
"webapp/**/*",
"node_modules/@sapui5/ts-types/types",
]
}
With removal of the typeof
keyword in the constructor functions @param
declaration we do get some code completion but none are from the "native" TSServer but rather from the aforementioned UI5 plugin (as can be identified by the providers hint). And it is rather crude as it seems to simply infer what getInterface
would technically return, throwing away our own type merging declaration above it.
Here we can see both the sap.ui.base.Object
and sap.ui.base.EventProvider
methods as code completion by the TSServer.
After having a chat with Peter, we decided to move to newer UI5 type declarations, so instead of using the legacy UI5 types ts-types, we moved to the new types (more info regarding UI5s types here). This can have a few drawbacks due to the mismatch of types and actual used UI5 version but I already discussed that with Peter and Andreas as well and it's something you have to take into consideration. In this case, the positives outweigh the negatives.
We can now make better use of the native JSDoc integration of TypeScript by using the TS import types syntax to pull in the default exports of UI5s .d.ts
((global) type declaration) files. This properly resolves the types in both, 4.X.X
and 5.X.X
TypeScript versions.
A great help was the demo repository from Andreas Kunz. Here we found not only some infos regarding Type support in JS applications but also confirmation that the way we make use of JSDocs @typedef
directive makes sense.
Also make sure to use typeof
where appropriate!
In case of
sap.ui.require(...)
andsap.ui.define(...)
calls, the parameters given to the callback function are not instances of Controller and other UI5 classes, but the parameters are the types/classes themselves! Hence an additional typeof operator needs to be added when specifying the types of the callback parameters.
Note
We do not use a tsconfig
though, we're still making use of a jsconfig
- in the end, same thing. 😉
{
"compilerOptions": {
"types": ["@sapui5/types", "@types/qunit", "@types/sinon"] // <<< resolve types by npm package name, instead of filepaths, thanks Peter!
},
"include": ["webapp/**/*"]
}
This project has been generated with 💙 and Easy-UI5