'What is the TypeScript equivalent of "PropTypes.oneOf" (restrict a variable to subset of values)

In React I can restrict a variable to subset of values, like

PropTypes.oneOf(['Home', 'About']),

How do I do that in TypeScript?

PS: I am not using TypeScript with React.



Solution 1:[1]

You can use enum.

Enums allow us to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases.

enum vs union-type

  • Union types are a compile time concept
  • Enums are real objects that exist at runtime
  • You can iterate over an enum
  • ... see this question

Example with enums:

enum PostStatus {
    DRAFT = "DRAFT",
    READY = "READY",
    PUBLISHED = "PUBLISHED",
}


class Post {
    constructor(private status: PostStatus) {
        this.status = status;
    }
}

const myPost = new Post(PostStatus.DRAFT);

console.log(myPost);

function doStuff(postStatus: PostStatus) {
    switch (postStatus) {
        case PostStatus.DRAFT: 
            console.log('Still working on it');
            break;
        case PostStatus.PUBLISHED:
            console.log('Done.');
        break;
        default:
            console.log('Other ...');
    }
}

Example with union type:

type PostStatus = "DRAFT" | "READY" | "PUBLISHED";


class Post {
    constructor(private status: PostStatus) {
        this.status = status;
    }

}

const myPost = new Post("DRAFT");
console.log(myPost);

function doStuff(postStatus: PostStatus) {
    switch (postStatus) {
        case "DRAFT": 
            console.log('Still working on it');
            break;
        case "PUBLISHED": 
            console.log('Done.');
            break;
        default:
            console.log('Other ...');
    }
}

Solution 2:[2]

Only one type among several one is a union type, and in your case a union of string literal.

You can convert an array of string literals into a union of string literals as follow:

If you do have a const array or string you can define a type:

const menuList = ["Home", "About"] as const;
type menuName = typeof menuList[number] // "Home" | "About"

If you do already have a type with the array just do:

type menuList = ["Home", "About"];
type menuItem = menuList[number] // "Home" | "About"

Solution 3:[3]

Here is a solution using an enum type, react proptypes and typescript props

export enum AppPage {
  Home = 'Home',
  About = 'About',
}
export MyComponentProps = {
  page: AppPage
}
export MyComponentPropTypes = {
  page: PropTypes.oneOf<AppPage>(Object.values(AppPage)).isRequired
}

export MyComponent = (props:MyComponentProps) => {
  return <div></div>
}

MyComponent.propTypes = MyComponentPropTypes

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 useless