Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript interface type with optional keys of different types and strictNullChecks

Tags:

typescript

I am trying to create the following interface in typescript:

type MoveSpeed = "min" | "road" | "full";

interface Interval {
  min?: number,
  max?: number
}

interface CreepPlan {
  [partName: string] : Interval;
  move?:    MoveSpeed;
}

However, this syntax is invalid. The compiler says Property 'move' of type '"min" | "road" | "full" | undefined' is not assignable to string index type 'Interval'..

I am using the compiler option strictNullChecks:true, which is why undefined is included implicitly for the move? key.

However, this syntax is valid:

type MoveSpeed = "min" | "road" | "full";

interface Interval {
  min?: number,
  max?: number
}

interface CreepPlan {
  [partName: string] : Interval;
  move:    MoveSpeed;            // 'move' is required
}

I want to express the idea "CreepPlan consists of string:Interval pairs, except the optional 'move' key which is a string:MoveSpeed pair." Is it possible to express this in typescript?

like image 325
Oliver Avatar asked Oct 06 '16 19:10

Oliver


1 Answers

You stated that all properties on CreepPlan have Interval-type values when you wrote:

interface CreepPlan {
  [partName: string] : Interval;
}

i.e., any and every string-index-accessible property of CreepPlan will be an Interval. This applies to move as well, since foo['move'] is the same as foo.move.

However, looking at Interval, there's no required structure to it:

interface Interval {
  min?: number,
  max?: number
}

There are no required fields in that contract, but it does require an object. It will happily accept an empty object, but it requires some object that could have a min and max properties.

Your MoveSpeed type, on the other hand, allows undefined:

Property 'move' of type '"min" | "road" | "full" | undefined' is not assignable to string index type 'Interval'.

Thus, Interval must be an object with no required properties (which string can easily meet) but does not allow undefined, which MoveSpeed does allow.

Your types are disjoint, but it's not obvious until you resolve them out once or twice.

like image 74
ssube Avatar answered Nov 12 '22 18:11

ssube