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
Second+ level "metadata" inheritance issues #338
Comments
As a workaround at least typing the static readonly metadata: object = { works and might be more elegant than the two suggestions so far, see this sandbox example. Of course rather than I have to admit that at first glance I do not understand why it is not sufficient to do this type assignment in the base class "ManagedObject", but it has to be done in the direct superclass. Probably because the typing itself of the field is not inherited, it "only" has to conform. I'd love to find a solution which avoids extra things to be added to the TS control code, but for someone facing this issue right now, this might be a viable workaround. |
We would benefit from microsoft/TypeScript#33892 here. |
Hi @akudev, I think it would be good idea to document this limitation somewhere. I got my answer and this issue can be closed, however, if you want to leave it open before microsoft/TypeScript#33892 gets resolved, I don't mind. |
The problem is now mentioned at https://github.com/SAP/ui5-typescript/blob/main/packages/ts-interface-generator/README.md#second-level-inheritance |
Hi @akudev, I interfaced the metadata, from what I could find is usable in it and starting from the sap.ui.base.ManagedObject class: export interface DnDMetadata {
droppable: boolean,
draggable: boolean
}
export interface ForwardingMetadata {
idSuffix?: string,
getter: string,
aggregation: string,
forwardBinding?: boolean
}
export interface AggregationMetadata {
type: string,
multiple?: boolean,
singularName?: string,
visibility?: "hidden" | "public",
bindable?: boolean | "bindable",
forwarding?: ForwardingMetadata,
selector?: string,
dnd?: boolean | DnDMetadata,
group?: "Accessibility" | "Appearance" | "Behavior" | "Data" | "Designtime" | "Dimension" | "Identification" | "Misc"
}
export interface AssociationMetadata {
type: string,
multiple?: boolean,
singularName?: string,
visibility?: "hidden" | "public",
group?: "Accessibility" | "Appearance" | "Behavior" | "Data" | "Designtime" | "Dimension" | "Identification" | "Misc"
}
export interface PropertyMetadata {
type: string,
visibility?: "hidden" | "public"
byValue?: boolean
group?: "Accessibility" | "Appearance" | "Behavior" | "Data" | "Designtime" | "Dimension" | "Identification" | "Misc"
defaultValue?: unknown,
selector?: string,
bindable?: boolean | "bindable"
}
export interface EventParamterMetadata {
type: string
}
export interface EventMetadata {
allowPreventDefault?: boolean
parameters?: Record<string, EventParamterMetadata | string>
}
export interface MetadataObjectMetadata {
library?: string,
defaultProperty ?: string,
defaultAggregation?: string,
properties?: Record<string, PropertyMetadata | string>,
events?: Record<string, EventMetadata>,
aggregations?: Record<string, AggregationMetadata | string>,
associations?: Record<string, AssociationMetadata | string>,
specialSettings?: Record<string, unknown>,
interfaces?: string[],
publicMethods?: string[],
abstract?: boolean,
final?: boolean,
dnd?: boolean | DnDMetadata,
deprecated?: boolean
} It helps a lot to write the metadata quickly and correctly. But the interfaces for the metadata would still have to be adapted so that also the classes sap.ui.base.ManagedObject is based of are considered. Example: static readonly metadata: MetadataObjectMetadata = {
properties: {
test: "string"
}
} |
@Revest117 thanks for your preparation work. Despite the lack of reaction here, we haven't ignored this topic, but the implementation is tricky: you know, the type definitions of UI5 are generated from the JSDoc, so the proper way would be to specify these types in JSDoc and let the generator do its job. This would allow maintaining the types together with the code, which would help with keeping both consistent with each other. However, I haven't found a good way to do this so far. Problems include (IIRC):
Of course we could just write the whole thing in TypeScript and add it during the generation step. But this would mean maintaining the documentation of the structure twice: In JSDoc fulltext for the SDK documentation and in TypeScript with proper typing of the objects. Sooner or later they would differ. Anyway, from my perspective, the full set of standard metadata object definitions on all relevant levels up to "Control" would look like as below.
The naming is still open, the parameter is called "ClassInfo" in the documentation. But the simpler *Metadata names you chose won't work because there are already classes like "ElementMetadata" etc. in UI5 and using them twice would cause confusion. So either -MetadataObject or -ClassInfo, I would say. Maybe the latter, because the former sounds funny in some combinations. This is just to sum up the current state. export interface BaseObjectMetadataObject {
interfaces?: string[];
publicMethods?: string[];
abstract?: boolean;
final?: boolean;
// TODO: used, but not documented in Object.js:
deprecated?: boolean;
}
export interface ManagedObjectMetadataObject extends BaseObjectMetadataObject {
library?: string;
properties?: Record<string, PropertyMetadataObject | string>;
defaultProperty?: string;
aggregations?: Record<string, AggregationMetadataObject | string>;
defaultAggregation?: string;
associations?: Record<string, AssociationMetadataObject | string>;
events?: Record<string, EventMetadataObject>;
specialSettings?: Record<string, unknown>;
}
export interface ElementMetadataObject extends ManagedObjectMetadataObject {
dnd?: boolean | DnDMetadataObject;
}
export interface ControlMetadataObject extends ElementMetadataObject {
// nothing added
}
export interface PropertyMetadataObject {
type: string | string[];
visibility?: "hidden" | "public"; // default: "public"
byValue?: boolean;
group?: "Accessibility" | "Appearance" | "Behavior" | "Data" | "Designtime" | "Dimension" | "Identification" | "Misc";
defaultValue?: unknown;
bindable?: boolean | "bindable";
selector?: string;
}
export interface AggregationMetadataObject {
type: string;
multiple?: boolean;
singularName?: string;
visibility?: "hidden" | "public"; // default: "public"
bindable?: boolean | "bindable";
forwarding?: ForwardingMetadataObject;
selector?: string;
// TODO: the following is only available for aggregations from Element or Control
dnd?: boolean | DnDAggregationMetadataObject;
// TODO: the following is not documented in the SDK
group?: "Accessibility" | "Appearance" | "Behavior" | "Data" | "Designtime" | "Dimension" | "Identification" | "Misc";
}
export interface AssociationMetadataObject {
type: string;
multiple?: boolean;
singularName?: string;
visibility?: "hidden" | "public";
// TODO: the following is not documented in the SDK
group?: "Accessibility" | "Appearance" | "Behavior" | "Data" | "Designtime" | "Dimension" | "Identification" | "Misc";
}
export interface EventMetadataObject {
allowPreventDefault?: boolean;
parameters?: Record<string, EventParameterMetadataObject | string>;
}
export interface EventParameterMetadataObject {
type: string;
}
export interface DnDMetadataObject {
droppable?: boolean;
draggable?: boolean;
}
export interface DnDAggregationMetadataObject extends DnDMetadataObject{
layout: "Vertical" | "Horizontal"; // default: "Vertical"
}
export interface ForwardingMetadataObject {
idSuffix?: string;
getter?: string;
aggregation: string;
forwardBinding?: boolean;
} |
...in type names. Needed in particular for the newly to-be-introduced sap.ui.base.Object.$ObjectMetadata etc. Related to SAP/ui5-typescript#338 Change-Id: I70c77de47ec5bd75373b04214d8401d7a272aff5
FYI: we have enriched the JSDoc processing to enable specifying inheritance in |
...in type names. Needed in particular for the newly to-be-introduced sap.ui.base.Object.$ObjectMetadata etc. Related to SAP/ui5-typescript#338 Cherry picked from SAP/openui5@7deccb5c7.
Related to SAP/ui5-typescript#338 Change-Id: Ida726a9ced5a9c322694576f9c4d73dd5609e2a0
Contains the following changes: * [INTERNAL] JSDoc: do not show a module for namespaces without exports When a namespace is not exported by a module, don't show a module for the namespace in the SDK. This prevents useless module information for purely virtual namespaces like sap.ui.base, sap.ui.model.json etc. Cherry picked from SAP/openui5@396262641. * [INTERNAL] jsdoc publish.js: type parser: accept underscores and $ signs ...in type names. Needed in particular for the newly to-be-introduced sap.ui.base.Object.$ObjectMetadata etc. Related to SAP/ui5-typescript#338 Cherry picked from SAP/openui5@7deccb5c7. * [INTERNAL] JSDoc publish.js: write type of @typedefs to api.json as "extends" - when the @typedef has properties and is not a type alias or function prototype Cherry picked from SAP/openui5@5c496b23d. * [INTERNAL] JSDoc: do not write 'module' info for borrowed APIs (part 2) This is a follow-up to SAP/openui5@9d3fccd91) which only handled the 'module' and 'export' properties and only for borrowed methods. The same logic now applies to the 'resource' property and also to borrowed properties (fields) and events. Cherry picked from SAP/openui5@d6215d715.
Ok, with SAP/openui5@8f935aa the type definitions for the "metadata" objects have landed. |
Available since 1.110 Related to SAP/ui5-typescript#338
- Make use of MetadataOptions type - Update to ts-interface-generator 0.6.2 - Update to UI5 1.114.0 - Update to TypeScript 5.0 Related: SAP/ui5-typescript#338
- Since 1.110.0, the "MetadataOptions" type allows full typing of the control metadata. Also, specifying this type - or just "object" below 1.110.0 - enables inheriting from such controls (cf. SAP/ui5-typescript#338). Both is done by this change. - ts-interface-generator has been extended with JSDoc generation; update to this version. - Also .gitignore any content in the "test" folder (which houses generated trial projects)
Using the MetadataOptions type for the metadata (or just "object" for versions below 1.110.0) solves this issue. All related samples have been updated (or have at least a PR to do so). Closing. |
Thank you a lot! |
There are conflicts with extending the class which extends standard UI5 class.
Example:
MyControl
extendsControl
, containstest
propertyOneMoreControl
extendsMyControl
, containsanotherTest
propertyOneMoreControl
gets error:Class static side 'typeof OneMoreControl' incorrectly extends base class static side 'typeof MyControl'.\n The types of 'metadata.properties' are incompatible between these types.\n Property 'test' is missing in type '{ anotherTest: string; }' but required in type '{ test: { type: string; }; }'.
There are two ways of dealing with it:
OneMoreControl
fromMyControl
, but I guess it would fail at runtime, because, if I recall correctly, metadata field is removed at runtime by UI5 framework.@ts-expect-error
Both options seems to be bad.
Any suggestions? Thanks!
The text was updated successfully, but these errors were encountered: