Home > OS >  How can I set a type of an Array so it is a keyof an interface?
How can I set a type of an Array so it is a keyof an interface?

Time:11-22

This is quite hard for me to explain, as I'm not sure what to call it. I have a interface and I want to set some properties using an array element as such:

interface MyStuff {
  key?: boolean;
};

var myThing: MyStuff = {};

var MyStuffArray: /* magic code */ = [];

MyStuffArray.push("key");

for(var p of MyStuffArray) {
  myThing[p /* magic code */] = true;
};

magic code being the area where I don't know what to put it as; because MyStuffArray can be only filled with keys from MyStuff.

I have tried myThing[p as keyof MyStuff] = true; but I get an error: Type 'boolean' is not assignable to type 'never'.

This works: (myThing as any)[p] = true, however I feel like this is bad practice when you have to use the any keyword in any situation.

If it helps: I do not want MyStuffArray to be filled with keys of MyStuff! I just want it so MyStuffArray can be filled with possible keys of MyStuff.

CodePudding user response:

You could use the keyof operator for the array declaration, and test for the property before doing an assignation, like this:

interface MyStuff {
    key?: boolean;
    other?: string;
};

var myThing: MyStuff = {};

var MyStuffArray: (keyof MyStuff)[] = [];

MyStuffArray.push('key');

for (var p of MyStuffArray) {
    if (p === 'key') {
        myThing[p] = true;
    }
};

CodePudding user response:

The simplest way (and preferable is to just use keyof keyword However, If you'd like to achieve even more type safety you could go ahead with the following code. It will keep you from pushing the same key to the array twice.

type UnionToIntersection<U> = (
  U extends never ? never : (arg: U) => never
) extends (arg: infer I) => void
  ? I
  : never;

type UnionToTuple<T> = UnionToIntersection<
  T extends never ? never : (t: T) => T
> extends (_: never) => infer W
  ? [...UnionToTuple<Exclude<T, W>>, W]
  : [];

//////////////////////////
//////// your code ///////

interface MyStuff {
  key?: boolean;
};

var myThing: MyStuff = {};

// Only one element 'key' is possible in the array
var myStuffArray: UnionToTuple<keyof MyStuff> = ['key'];

for(var p of myStuffArray) {
  myThing[p /* magic code */] = true;
};
  • Related