2

I have an array of static strings that I want to create an interface off of. The best way to explain this is to show an example of psedo-interfaces:

const types = ["error", "warning", "success"];

interface Modal {
    type: keyof types;
}

I need to use the types, in order, in my actual js so I was hoping there was a way to express this in the interface so I don't have to duplicate the values in the array and the interface. Is this possible?

0

2 Answers 2

7

You can get this, but the problem is that types is widened to string[], which loses the information about which specific strings are in the array, and in which order.

If all you want is the particular strings and don't care about the order, you can make a helper function which uses a trick to get types to be inferred as a narrower type (you can read this issue for more info about how to prevent widening):

const narrowArray = <K extends string>(...arr: K[]) => arr;

And use it:

const types = narrowArray("error", "warning", "success");

Now types is inferred to be Array<"error"|"warning"|"success">. If you want Modal['types'] to be one of those strings (not clear from your post... keyof certainly won't do it), then you can do this:

interface Modal {
    type: (typeof types)[number];  // "error" | "warning" | "success"
}

That should work for you.


Also relevant: starting in TypeScript 3.0 there will be a way to infer tuple types which will let you keep track of the ordering of types as well. It will be like this:

// only works in TS3.0 and up
const narrowTuple = <K extends string[]>(...arr: K) => arr;
const types = narrowTuple("error", "warning", "success");
// types is inferred as type ["error", "warning", "success"]

Now types is inferred as the triple ["error", "warning", "success"], and so at compile time TypeScript will know that, for example, types[1] is specifically "warning". (You don't need to keep track of ordering for the Modal['type'] definition above, unless I'm not understanding what you want Modal['type'] to be.)


Hope that helps. Good luck!

Sign up to request clarification or add additional context in comments.

3 Comments

Wow. I knew someone would have some way to do this. I actually do care about the order of const types in my case (don't need to get into details why). Are you saying that the types array isn't necessarily in the order that I specify?
The actual array at runtime will be in the order you specify. It's just that the compiler doesn't keep track of it, so you won't be able to ask the compiler which element is at which index.
Ah, gotcha. I just need it to be in order at runtime. Thanks for the help! Greatly appreciated.
3

Sorry there is no way to dynamically create an interface at run time. It would defeat the whole purpose of static typing.

You could however do something like this:

export enum StatusCodes {
  error = 'error,
  success = 'success',
  warning = 'warning'
}
const types: Array<StatusCodes> = [StatusCodes.error, StatusCodes.success, StatusCodes.warning]

interface Modal {
  type: StatusCodes
}

2 Comments

Yeah I didn't think it was possible, but people always seem to find ways to hack typings so I didn't know if I was missing anything. Thanks for the reply!
@jas7457 There kinda is a way, by just listing out the options in the type declaration. See my answer if you don't understand.

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.