I have an object typed Partial. I want to check if a given key exists in the object. The below code doesn't work. Does anybody know how to? I'm using Typescript 4.6. Thanks in advance.
type Name = 'dog' | 'cat' | 'bird'
function(obj: Partial<Record<Name, number>>, name: Name) {
// check a given name exists in obj
if (name in obj) {
const v = obj[name] // number or undefined
}
// Wait, how about dot notation?
if ('dog' in obj) {
const v = obj.dog // number or undefined
}
if (obj.dog !== undefined) {
const v = obj.dog // number or undefined
}
}
CodePudding user response:
TypeScript doesn't refine the type of your obj
argument, even within each of those conditions it will still be Partial<Record<Name, number>>
.
However, you can narrow the type of a variable that was assigned the value of that property in obj
. For example:
type Name = 'dog' | 'cat' | 'bird'
function fn(obj: Partial<Record<Name, number>>, name: Name) {
// check a given name exists in obj
const v1 = obj[name];
if (v1) {
// v1: number
}
const v2 = obj.dog;
if (v2) {
// v2: number
}
}
TypeScript doesn't do that level of type narrowing where it would apply to only a single property of an object. I believe the only time when checking an object's properties can narrow the type of object is when you're working with a disciminated union.
This is why, for example, you can do things like this:
type MyType = {
key: 'a',
value: number,
} | {
key: 'b',
value: string;
};
function (arg: MyType) {
if (arg.key === 'a') {
// arg.value: number
} else {
// arg.value: string
}
}
CodePudding user response:
You could do like this:
type Name = 'dog' | 'cat' | 'bird'
function test(obj: Partial<Record<Name, number>>, name: Name) {
// First you assign the value to a const
const v = obj[name];
// then you test the value of that const
if(v !== undefined){
// do stuff with `v`, now type is inferred correctly
console.log(v);
}
}