Issue
I'm struggling a bit with checking if the property value of an object is undefined when I access it dynamically through bracket notation. Below is an example of my code.
function toBritishDate(date: Date | string): string {
console.log(date)
return "foo"
}
function myFunc() {
const project: { start_date?: string; end_date?: string } = {
start_date: '2023-09-13',
end_date: '2023-09-29',
};
const array: ("start_date" | "end_date")[] = ['start_date', 'end_date']
array.forEach((element) => {
if (project[element] !== undefined) {
console.log(toBritishDate(project[element]))
}
});
}
You can find a playground on this link.
When calling toBritishDate I get the following error on match.project[element]:
Argument of type 'string | undefined' is not assignable to parameter of type 'string | Date'. Type 'undefined' is not assignable to type 'string | Date'. (tsserver 2345)
It seems like match.project[element] !== undefined
only checks if the property exists, it doesn't check if the actual value is undefined. Does anyone know how I can check if the property exists, and that the value is not undefined?
Solution
This is a known missing feature, originally filed at microsoft/TypeScript#10530 and now currently tracked at microsoft/TypeScript#56389. TypeScript doesn't keep track of the identity of a key like element
when you perform an indexing like project[element]
. It only looks at the type, which for element
is the union type "start_date" | "end_date"
. So it analyzes your code as if it were like
declare const element1: "start_date" | "end_date";
declare const element2: "start_date" | "end_date";
if (project[element1] !== undefined) {
console.log(toBritishDate(project[element2])) // error, of course
}
which is obviously not safe. TypeScript would need to track the identity of the key to tell the difference between your safe code and the above unsafe code. It can't, right now, so that's what's happening.
Until and unless that's addressed, you'll need to work around it. The standard workaround is to copy your property into a new variable to sidestep the whole issue around indexing and identity:
const projectElement = project[element];
if (projectElement !== undefined) {
console.log(toBritishDate(projectElement)) // okay
}
Since projectElement
is just a single variable, the compiler can just perform regular old narrowing analysis on it, which works as you expect.
Answered By - jcalz
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.