Gagan Deep
Gagan Deep

Reputation: 53

Dynamic Keys and value type checking in typescript

I have started learning typescript. I am sure there might be a similar ticket as this but wanted a quick view into this.

i have keys
type keys = 'a' | 'e' | 'i' | 'o' | 'u';
I want these to restrict the possible a keys in an object
{
numbers : number;
symbols : string;
[key : keys] : string | number | boolean;
}

However i get this error An index signature parameter type cannot be a union type. Consider using a mapped object type instead. so i tried

{
numbers : number;
symbols : string;
[key in keys] : string | number | boolean;
}

but I got another error from TSLint. I hope if somebody can help me out with these with examples why and how do they vary? and solution Please.

The result I want is

key with only values of a, e, i, o, u and these Keys can have any of the string, number, boolean types of values.

Upvotes: 3

Views: 3300

Answers (2)

Milad
Milad

Reputation: 28590


    type keys =  'a' | 'e' | 'i' | 'o' | 'u'

    type Dynamic = {
      [index in  keys]: string | number | boolean
    }&{
      numbers : number;
      symbols : string;
    }

Upvotes: 0

jcalz
jcalz

Reputation: 328618

Mapped types are similar to index signatures, but they are not the same. As you discovered, the keys of index signatures can only be exactly string or number. Mapped types allow you to specify a narrower set of keys, but you can't add other properties to a mapped type.

What you can do is use an intersection:

type X = {numbers: number; symbols: string} & {[K in keys]: string | number | boolean}

// type X = {
//  numbers: number;
//  symbols: string;
// } & {
//  a: string | number | boolean;
//  e: string | number | boolean;
//  i: string | number | boolean;
//  o: string | number | boolean;
//  u: string | number | boolean;
// }

This is essentially the same as what you want, since the intersection A & B means that you must conform to both A and B.

Another way to represent this type is to use a mapped conditional type for the whole thing instead of an intersection. This will be more complicated-looking for you, but evaluates to something nicer for people to use:

type Y = { [K in "numbers" | "symbols" | keys]:
  K extends "numbers" ? number :
  K extends "symbols" ? string :
  string | number | boolean };

// type Y = {
// a: string | number | boolean;
// e: string | number | boolean;
// i: string | number | boolean;
// o: string | number | boolean;
// u: string | number | boolean;
// numbers: number;
// symbols: string;

Either way should work. Hope that helps; good luck!

Upvotes: 1

Related Questions