Menas
Menas

Reputation: 1269

How to nest enums in TypeScript?

Let's say I have a function like this but with many more possible values for the enum parameter:

enum API{
    userDetails = "/api/user/details",
    userPosts = "/api/user/posts",
    userComments = "/api/user/comments",
    postDetails = "/api/post/details",
    postComments = "/api/post/comments"
    //...
};

function callAPI(endpoint: API/*, some more params*/){
    // some code to deal with the specified endpoint...
}

callAPI(API.userComments);

The above code works fine, but I need to group the many values of the enum into an organized hierarchical structure in order to make things a little more organized... For example, it would be much better if the syntax for calling the API can be callAPI(API.user.comments) instead of callAPI(API.userComments).

I tried things like the below attempts but it looks like none were accepted as a valid syntax for typescript.

Attempt 1

enum API{
    user = {
        details : "/api/user/details",
        userPorts : "/api/user/posts",
        userComments : "/api/user/comments"
    }
    post = {
        postDetails : "/api/post/details",
        postComments : "/api/post/comments"
    }
}

Attempt 2

enum user {
    details = "/api/user/details",
    userPorts = "/api/user/posts",
    userComments = "/api/user/comments"
}
enum post {
    postDetails = "/api/post/details",
    postComments = "/api/post/comments"
}
enum API{
    user,
    post
}

Attempt 3

enum user {
    details = "/api/user/details",
    userPorts = "/api/user/posts",
    userComments = "/api/user/comments"
}
enum post {
    postDetails = "/api/post/details",
    postComments = "/api/post/comments"
}
enum API{
    user = user,
    post = post
}

Attempt 4

enum user {
    details = "/api/user/details",
    userPorts = "/api/user/posts",
    userComments = "/api/user/comments"
}
enum post {
    postDetails = "/api/post/details",
    postComments = "/api/post/comments"
}
enum API{
    user:user
    post:post
}

Upvotes: 3

Views: 3905

Answers (2)

watofundefined
watofundefined

Reputation: 374

My understanding is that it's not possible with enums - right hand side of an enum member can be either nothing, number, string, or another enum value. See https://www.typescriptlang.org/docs/handbook/enums.html for more details.

But you can easily achieve what you want with plain objects.

const API = {
  user: {
    details: "/api/user/details",
    posts: "/api/user/posts",
  },
  // ...
};

If you're worried that it might be modified, you can use Object.freeze.

If you need to pass the whole API object to a function via argument then you'll need to define an interface for it too, but otherwise autocomplete and checks should work just fine.

-------- edit

Adding types in case you find them useful:

export type ApiRoutes<TRoute extends string> = { [key in TRoute]: string };

export interface MyApi {
  user: ApiRoutes<"details" | "posts" | "comments">;
  post: ApiRoutes<"details" | "comments">;
}

Upvotes: 4

A_A
A_A

Reputation: 1932

You could wrap it inside a namespace:

namespace API{
    export enum User {
        details = "/api/user/details",
        posts = "/api/user/posts",
        comments = "/api/user/comments",
    }
    export enum Post {
        details = "/api/post/details",
        comments = "/api/post/comments",
    }
}

console.log(API.User.comments)
console.log(API.Post.details)

Upvotes: 9

Related Questions