Making a custom UISchema type Scoped in TypeScript

Hi, I am creating custom components to match our usages using uiTypeIs tester.

export const autocompleteJsonFormControlTester = rankWith(
  3,
  uiTypeIs("AutocompleteControl")
);

It all works but the typescript typing highlights an error when specifying the scope property passed to a UISchemaElement parameter. I see from the typing that the “ControlElement” type extends “Scoped”. How do I add my typescript type for AutocompleteControl to the JSONForms type so it knows that AutocompleteControl is Scoped?

Hi @J5live ,

The issue stems from the definition of the UISchemaElement type:

/**
 * A union of all available UI schema elements.
 * This includes all layout elements, control elements, label elements,
 * group elements, category elements and categorization elements.
 */
export type UISchemaElement = BaseUISchemaElement | ControlElement | Layout | LabelElement | GroupLayout | Category | Categorization | VerticalLayout | HorizontalLayout;

This marks your scope as an unknown property.

Solution 1: Cast to appropriate type

You should be able to define an interface like this for an autocomplete control.

import { BaseUISchemaElement, Scoped } from '@jsonforms/core';

interface AutocompleteControl extends BaseUISchemaElement, Scoped {
  type: 'Autocomplete';
}

You then need to explicitly cast your element to this type. Then it is recognized as a UISchemaElement because BaseUISchemaElement is allowed.

You can also directly cast you element to BaseUISchemaElement.

Solution 2: Use a UISchema option to identify the control in your tester

Each Control element can have arbitrary options like so:

{
  type: "Control",
  scope: "#/properties/users",
  options: {
    customAutocomplete: true
  }
}

Then, in your tester you can check this:

export const autocompleteJsonFormControlTester = rankWith(
  3,
  optionIs("customAutocomplete", true)
);

I would recommend solution 2.

We are going with solution 1 because we are incontrol of the schema. In the case of strings that represent money or dates we will use format in the data schema but for controls with data contracts we prefer to be explicit. For instance our autocompletes are backed by standard search URLs for selections that are passed in an options property.

In any case this works, It is mostly a concern for tests and not tripping our build linters. In the majority of cases the schemas will come in as JSON from the server. It would be nice if there was a documented way to just extend UISchemaElement using declare module, but I haven’t been able to figure out the right way to describe it so that the JSONForms interface accepts the new type. Note I used this for brevity:

export interface AutocompleteControlElement extends Omit<ControlElement, 'type'> {
  type: 'AutocompleteControl';
}

This way you only have one import and are a bit shielded from future versions extending Control with other interfaces.

1 Like