Typescript interface type with optional keys of different types and strictNullChecks
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.
As described in the typescript docs if you use indexable properties then all the return type of all the other properties should be assignable to the return type of the index return type.
That's because foo['bar']
and foo.bar
are the same.
So why does this work?
interface CreepPlan {
[partName: string]: Interval;
move: MoveSpeed;
}
Because any MoveSpeed
is a valid Interval
value (it is an interval with undefined both min
/max
.
Why doesn't this work?
interface CreepPlan {
[partName: string]: Interval;
move?: MoveSpeed;
}
move?
has type MoveSpeed
plus the undefined
type. If is has the undefined value then it is not assignable to Interval
so the compiler correctly shows error.
How can you fix this? Simply make the indexer have undefined
as a valid value:
interface CreepPlan {
[partName: string]: Interval | undefined;
move?: MoveSpeed;
}