Julo
Julo

Reputation: 75

Typescript interface from array type

I need to force an array to have a specific set of values that should be then the keys of my interface. I can force the array with

type SomeProperties = ['prop1', 'prop2', 'prop3'];

but I don't know how to force an interface to have those properties. I tried something like

type MyInterface = {
  [key in keyof SomeProperties]: string;
}

but obviously the keys of an array are just numbers so my interface become

interface MyInterface {
  0: string;
  1: string;
  2: string;
}

instead of the wanted interface

interface MyInterface {
  prop1: string;
  prop2: string;
  prop3: string;
}

Do you know if there is a way to achieve this in Typescript?

It would be useful because I need to iterate on some properties to "clone" an object and I also need to access to those properties easily. Repeating the properties in both type and interface is a bit fragile for me.

Upvotes: 7

Views: 6254

Answers (3)

jcalz
jcalz

Reputation: 327624

As you note, the strings you're trying to access aren't the keys of SomeProperties, but the elements of SomeProperties.

You can use the indexed access operator here: if K is a key (or a union of keys) of T, then T[K] is the property type (or union of property types) corresponding to accessing the K key(s) of T.

Tuples and arrays accept number as a key type, so you want to use SomeProperties[number] to give you the union "prop1"|"prop2"|"prop3":

type SomeProperties = ['prop1', 'prop2', 'prop3'];

type MyInterface = {
  [K in SomeProperties[number]]: string;
}

const myInterface: MyInterface = {
  prop1: 'this',
  prop2: 'works',
  prop3: 'now'
}

Playground link to code

Upvotes: 7

Roman Rokon
Roman Rokon

Reputation: 331

Update to Madara's answer for future readers.

These sorts of operations can only be applied to types, not interfaces.

I don't know since when, but nowadays you can do this with interfaces too.

type SomeProperties = 'prop1' | 'prop2' | 'prop3';

interface MyType extends Record<SomeProperties, string> {
   // other properties
}

It is equivalent to the following:

type SomeProperties = 'prop1' | 'prop2' | 'prop3';

type MyType = Record<SomeProperties, string>;

Upvotes: 0

Madara&#39;s Ghost
Madara&#39;s Ghost

Reputation: 174937

Worth noting: You can't iterate an tuple type in TypeScript

Actually, you can! Since TypeScript 3.1 you can safely use tuple types in mapped types like objects.

These sorts of operations can only be applied to types, not interfaces.

type SomeProperties = 'prop1' | 'prop2' | 'prop3';

type MyType = Record<SomeProperties, string>;

// equivalent to
// type MyType = {
//   [key in SomeProperties]: string
// }

Types and interface are the same from the perspective of the consumer (when you ask for a MyType, you don't care if it's an interface or a type, they're the same at that point)

Upvotes: 6

Related Questions