Let's say I have a type Fields
export type NodeId =
| "a-index"
| "b-index"
| "c-index"
export type Fields = {
[id in NodeId]?: {
[sectionId: string]: {
[name: string]: string;
};
}
};
Why does the first set error with Object is possibly 'undefined'
, but not the second set?
const test: Fields = {};
const id = "a-index";
// Why does this error
let resultA;
if (test[id]) {
resultA = test[id]["somesection"]
^^^^^^^^
error TS2532: Object is possibly 'undefined'.
}
// But this works fine?
let resultB;
if (test["a-index"]) {
resultB = test["a-index"]["somesection"]
}
The only difference being that I assigned id
to a variable. Even explicitly typing id
as NodeId
doesn't satisfy typescript.
This is a known issue, microsoft/TypeScript#10530 . The problem is that the compiler only spends time narrowing the type of an object property if the property access is direct , either by using a dotted identifier or by using bracket index with a string literal. So your resultB
version works:
let resultB;
if (test["a-index"]) {
resultB = test["a-index"]["somesection"]
}
But the resultA
version doesn't because id
, even though it is a const
whose type is the literal "a-index"
, is a variable and the compiler doesn't do narrowing for it. According to microsoft/TypeScript#10565 , an initial attempt to address this, adding this functionality significantly worsens the compiler perfomance. I guess having to check every possible indexing-into-an-object is more expensive than the potential control flow narrowing saves you.
The workaround here, in the case where you can't just replace id
with a string literal, is to do the property access once and save its result to a new variable. Then type guards should work on this variable as expected:
let resultA;
const testId = test[id];
if (testId) {
resultA = testId["somesection"]
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.