How do you check for undefined when using an expression as the property name of object in Typescript strict mode?

69 Views Asked by At

Consider the following code:

type Props = 'foo' | 'bar';
type ParRec = Partial<Record<Props, string>>;

function doSomething (item: ParRec) {
  const props: Props[] = ['foo', 'bar'];
  return props.map((prop) => {
    if(item[prop]) {
      const result: string = item[prop];
      return { result };
    }
    return {};
  });
} 

typescript complains with ts(2322) where const result is declared that string | undefined is not assignable to type string.

The conditional truthy check if(item[prop]) should ensure that it is not undefined.

This seems to only be a problem when using an expression as the property name of item, as the following code has no problem:

function doSomething (item: ParRec) {
  const props: Props[] = ['foo', 'bar'];
  return props.map((prop) => {
    if(item.foo) { // using item['foo'] also works fine
      const result: string = item.foo;
      return { result };
    }
    return {};
  });
} 

I could understand if the object definition was more ambiguous, but I am using the same union type to define both the expression I am using as a property name, as well as the object type definition itself. Is there another way to ensure that item[prop] is not undefined I am not aware of for strict mode?

I am using typescript 4.8.4, and this code is made to simply describe the type error, not to represent any actual functionality.

1

There are 1 best solutions below

1
Iain Shelvington On BEST ANSWER

You can assign the result of item[prop] to a variable and use the variable in the check

Playground

function doSomething (item: ParRec) {
  const props: Props[] = ['foo', 'bar'];
  return props.map((prop) => {
    const result = item[prop]; // string | undefined
    if(result) { // narrowed to string
      return { result };
    }
    return {};
  });
}