jas7457
jas7457

Reputation: 1782

Create TypeScript interface based off of static array

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?

Upvotes: 2

Views: 371

Answers (2)

jcalz
jcalz

Reputation: 327819

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!

Upvotes: 7

andrew ferguson
andrew ferguson

Reputation: 189

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
}

Upvotes: 3

Related Questions