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, withit thinks that the
fooproperty will always exist - it'll never fail and turn intoundefinedvia optional chaining.In contrast, with A's:
Since the
fooproperty is optional here, it's not sure to exist (to Typescript), so the?.may result in no property being found andundefinedbeing the result.You can make it clear that not all properties on
Bwill necessarily have thebarobject by alternating withundefinedin the object value type:resulting in
bbbeing typed asnumber | undefined.