typescriptobjectexpressionstrict

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


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.


Solution

  • 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 {};
      });
    }