Oliver Oliver - 1 month ago 17
TypeScript Question

Typescript interface type with optional keys of different types and strictNullChecks

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?

Answer

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.

Comments