I defined two interfaces. The first one has an optional field, the second one has an index signature:
interface A {
foo?: { bar: number };
}
interface B {
[s: string]: { bar: number };
}
Why does the first interface give me a result of type number | undefined
when I access the property using optional chaining, whereas the second one gives only type number
?
const a: A = {};
const aa = a.foo?.bar;
// const aa: number | undefined
const b: B = {};
const bb = b.foo?.bar;
// const bb: number
Because B is indexed by [s: string]
, it believe that any valid string key will result in the value of { bar: number }
being accessed. So, with
const b: B = {};
const bb = b.foo?.bar;
it thinks that the foo
property will always exist - it'll never fail and turn into undefined
via optional chaining.
In contrast, with A's:
interface A {
foo?: { bar: number };
}
Since the foo
property is optional here, it's not sure to exist (to Typescript), so the ?.
may result in no property being found and undefined
being the result.
You can make it clear that not all properties on B
will necessarily have the bar
object by alternating with undefined
in the object value type:
interface B {
[s: string]: { bar: number } | undefined;
}
resulting in bb
being typed as number | undefined
.