Sharcoux
Sharcoux

Reputation: 6085

Specify a different type for some keys of a dictionary in Typescript

I am trying to do something like that in Typescript :

type A = 'stuff'
type B = {
  [x: string]: {
    active?: {
      [name: string] : A
    }
    [name: string] : A
  }
}

But I get : Property 'active' of type '{ [name: string]: A; } | undefined' is not assignable to string index type 'A'.

What I understand is that active is also recognized as a member of [name: string]. Is there aanything I can do to precise that active might contain something different from the other keys?

I hope this is not a duplicate, I had a hard time finding the good way to describe the problem in Google.

** Update: **

The following code fail with Typescript

type ImageName = 'test'
type IconEntry = { [name: string]: ImageName }
type Icons = {
  [namespace: string]: IconEntry & {
    active?: IconEntry;
  };
}

const icons: Icons = {
  buttons: {
    switch: 'test',
    active: {
      switch: 'test'
    }
  }
}
Type '{ switch: "test"; active: { switch: "test"; }; }' is not assignable to type 'IconEntry & { active?: IconEntry | undefined; }'.
  Type '{ switch: "test"; active: { switch: "test"; }; }' is not assignable to type 'IconEntry'.
    Property 'active' is incompatible with index signature.
      Type '{ switch: "test"; }' is not assignable to type '"test"'.(2322)
input.ts(4, 3): The expected type comes from this index signature.

Upvotes: 0

Views: 187

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074276

The only difference I see in active is that it's A | undefined instead of just A. You can define that with an intersection type:

type A = "stuff";
type B = {
  [x: string]: {[name: string] : A} & {active?: A}
// −−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
};

With that, assuming you have let b: B, then b["x"].active will have the type "stuff" | undefined and b["x"].foo will have the type "stuff".

On the playground

The same approach works if you want active to have a completely different type, unrelated to A:

type A = "stuff";
type A1 = "other stuff";
type B = {
    [x: string]: { [name: string]: A } & { active?: A1 }
};

Upvotes: 3

Related Questions