0
 enum ROUTES {
  REQUEST_OTP = 'REQUEST_OTP',
  LOGIN = 'LOGIN',
}

export const urls: { [key: string]: string } = {
  [ROUTES.REQUEST_OTP]: '/v1/auth/otp',
  [ROUTES.LOGIN]: '/v1/auth/login',
};

export function getUrl(route: string) {
  return BASE_URL + urls[route];
}

Is there a better way to write ROUTES enum rather than repeatedly writing string literals next to it?

There seems to be a repetition of code in the my code writing the string enums.

Trying out mapped types:

 type ROUTE_KEY = 'REQUEST_OTP' | 'LOGIN';

export const urls: { [key: string]: string } = {
  REQUEST_OTP: '/v1/auth/request-otp',
  LOGIN: '/v1/auth/login/?version=v2',
};

export function getUrl(route: ROUTE_KEY) {
  return BASE_URL + urls[route];
}
3
  • I usually use a config.ts file to store such urls, and load these to the ENV. So, the default values will be in the config and it can be overridden by setting the env var too. Commented Aug 8, 2020 at 8:28
  • You'll want to use { [key: ROUTE_KEY]: string } Commented Aug 8, 2020 at 14:46
  • 2
    Or even better, type ROUTE_KEY = keyof typeof urls; (with urls being declared as const) Commented Aug 8, 2020 at 14:47

2 Answers 2

1

The key to avoiding redundancy in this situation is to compute your types from your values while leveraging type inference. Every JavaScript expression has a corresponding TypeSript type. As Bergi metioned, we can obtain the type from a value by using the typeof operator in type position. Together with the keyof type operator we use this to compute a union type consisiting of all property keys in urls.

export const urls = {
  EQUEST_OTP: '/v1/auth/request-otp',
  LOGIN: '/v1/auth/login/?version=v2'
};

export type RouteKey = keyof typeof urls;

export function getUrl(route: RouteKey) {
  return BASE_URL + urls[route];
}

Playground Link

In the above, we used typeof type operator to obtain the type of the value urls, which is

{
  REQUEST_OTP: string,
  LOGIN: string
}

We then used the keyof type operator to compute a union type consisting of the property keys of the that type, which is

'REQUEST_OTP' | 'LOGIN'

Notice how the variable urls has no type annotation. The use of type inference not only increases brevity but also results in a far stronger type than { [key: string]: string }.

Alternately, we can actually could do without declaring the type alias RouteKey and just write

export function getUrl(route: keyof typeof urls) {
  return BASE_URL + urls[route];
}
Sign up to request clarification or add additional context in comments.

1 Comment

I want to point out that we should be appending the urls with URL here is the MDN docs; instead of using string concatenation, like new URL(urls[route], BASE_URL). If the person passes in an invalid URL, it will throw a TypeError object error.
0

It's not clear if this is better, because you're not specific about what is bad with your current sample. However, this is how I would write this:


type RouteKey = 'request-otp' | 'login';


export const urls: { [key: RouteKey]: string } = {
  'request-otp': '/v1/auth/otp',
  'login:': '/v1/auth/login',
};


export function getUrl(route: RouteKey) {
  return BASE_URL + urls[route];
}

1 Comment

This results in an error. Index signatures cannot be a union type. The correct type would be { [P in RouteKey]: string }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.