Skip to content

feat: export component option enums as string literal union types #5494

@hawkticehurst

Description

@hawkticehurst

🙋 Feature Request

Continuing a conversation from this thread.

Background:

Currently, there are a number of fast foundation component attribute value types that are defined with enums (i.e. TextFieldTypes, SelectPosition, and so on).

This is a non-issue when creating/using new web components based on these foundation components, however, once the new components are wrapped with fast-react-wrapper and used within a React application you will run into TS errors/issues along these lines:

// This does NOT work (i.e. TS Error: Type '"password"' is not assignable to type 'TextFieldType | undefined'.)
// TypeScript is looking for the enum type and will not allow a literal string value
<VSCodeTextField type="password"></VSCodeTextField>

An easy solution is to import/export these enums so they are consumable by downstream component libraries––however, this would result in what I think is a clunky/unintuitive developer experience:

// This works but is a bit clunky imo
import {TextFieldTypes} from "toolkit";
<VSCodeTextField type={TextFieldTypes.password}></VSCodeTextField>

As I explain more below, I think the ideal solution is to export or even convert these enums into string literal union types.

🤔 Expected Behavior

You should be able to write out the literal string value of any attribute without running into type errors.

😯 Current Behavior

FAST Foundation component attributes which are defined with enums and then wrapped as React components must import and use the enums to avoid type errors.

💁 Possible Solution

After a quick peek through the fast foundation source code it actually looks like most (if not all) of these enums are exported and thus a very easy solution would be for consumers of the foundation components to simply re-export these enums in their own component libraries for end-users to use.

With that said, I would ideally love to see FAST Foundation components provide or even convert instances of these attribute enums into string literal union types so that there is still type safety/restrictions, but end-users can simply type out the literal value versus being forced to import and use the enums.

For example:

// Instead of this
export enum TextFieldType {
    email = "email",
    password = "password",
    tel = "tel",
    text = "text",
    url = "url",
}

// Create and use this
export type TextFieldType = "email" | "password" | "tel" | "text" | "url";

In the above-mentioned thread @EisenbergEffect also left the following comment:

...Maybe we can provide some sort of typing that enables using either the enum or the string literal? Basically, I want to see if we can avoid a breaking change...

As of TypeScript v4.1 it should actually be possible to convert the enums into string literal unions with template syntax (this way there is one source of truth for the typings):

StackOverflow Reference

export enum TextFieldType {
    email = "email",
    password = "password",
    tel = "tel",
    text = "text",
    url = "url",
}

export type TextFieldLiteralType = `${TextFieldType}`;

From here both the enum and string literal union can theoretically be exported and used by consumers. With that said, I believe the really important part of ensuring that the string literal union type solution works is to update the foundation component type declarations.

For example, the text field type attribute should be updated to look something like so:

import { TextFieldType, TextFieldLiteralType } from "./text-field.options"; // <-- import both enum and string literal union type

/**
 * Allows setting a type or mode of text.
 * @public
 * @remarks
 * HTML Attribute: type
 */
@attr
public type: TextFieldType | TextFieldLiteralType = TextFieldType.text; // <-- Note the new type annotation
private typeChanged(): void {
    if (this.proxy instanceof HTMLInputElement) {
        this.proxy.type = this.type;
        this.validate();
    }
}

I have yet to test this, but I believe (??) this should ensure backward compatibility while also giving end-users the option to simply type out the literal values if they desire.

🔦 Context

We're planning on publishing a set of wrapped React components for the Webview UI Toolkit for VS Code and would ideally like an easy developer experience for toolkit consumers that does not require importing enums for various component attributes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions