Skip to content
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

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

Closed
hawkticehurst opened this issue Dec 31, 2021 · 7 comments · Fixed by #5745
Closed

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

hawkticehurst opened this issue Dec 31, 2021 · 7 comments · Fixed by #5745
Labels
area:fast-foundation Pertains to fast-foundation improvement A non-feature-adding improvement status:planned Work is planned

Comments

@hawkticehurst
Copy link
Member

hawkticehurst commented Dec 31, 2021

🙋 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.

@hawkticehurst hawkticehurst added the status:triage New Issue - needs triage label Dec 31, 2021
@hawkticehurst
Copy link
Member Author

Hope that the write-up was clear, let me know if there's anything I can clarify!

cc @EisenbergEffect @chrisdholt

@hawkticehurst
Copy link
Member Author

Also in terms of an immediate stop-gap solution for this issue, I think I'll be creating a new PR in the toolkit that simply re-exports all of the relevant fast foundation enums for toolkit developers to use.

But again I would love to see the addition of string literal union types so that using the enums is not a requirement.

@hawkticehurst hawkticehurst changed the title feat: export component option types as string literal union types feat: export component option enums as string literal union types Dec 31, 2021
@EisenbergEffect
Copy link
Contributor

I was thinking the same thing, in terms of updating the property with a union type. I think we're blocked on TS 4.1 for the moment, but we can still create the string unions literally.

@EisenbergEffect EisenbergEffect added area:fast-foundation Pertains to fast-foundation improvement A non-feature-adding improvement status:planned Work is planned and removed status:triage New Issue - needs triage labels Dec 31, 2021
@hawkticehurst
Copy link
Member Author

hawkticehurst commented Jan 4, 2022

That sounds great to me! Totally fine if you're blocked on TS 4.1 since template string conversion would only really be an ease of life improvement but not a requirement.

hawkticehurst added a commit to microsoft/vscode-webview-ui-toolkit that referenced this issue Jan 5, 2022
Description of changes

This is a temporary stop-gap solution to this [upstream issue](microsoft/fast#5494) where a handful of toolkit component attributes (when wrapped as React components) will result in TS type errors because the attributes/props require an enum as the value.

Once the upstream issue is resolved these changes should be reverted.
@hawkticehurst
Copy link
Member Author

Hey, checking in on the progress for this issue? We're about 1 month out from a 1.0 release for the toolkit and I would love to have this resolved before then if possible.

Also if you are all busy, I would be happy to tackle this issue and contribute back to FAST 😊

@EisenbergEffect
Copy link
Contributor

@hawkticehurst If you are able to contribute it, that would certainly help. We're bogged down in a bunch of other items right now and I'm afraid it might not get done in time for your release.

@hawkticehurst
Copy link
Member Author

No worries! I definitely understand that. This seems like a fairly straight forward issue so I'd be happy to have a crack at it in the next week or two!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:fast-foundation Pertains to fast-foundation improvement A non-feature-adding improvement status:planned Work is planned
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants