Typescript, how to reassign type after filtering by prop existance?

I have an array with:

const list: Readonly<ListProps> = {some values}

interface ListProps {
  type: 'radio' | 'check';
  style: 'text' | 'button';
  options: OptionProps[];
}

interface OptionProps {
  label: string;
  value: string;
  sublist?: ListProps;
}

I filtered out options to only leave those with sublist:

const nodesWithSublist: ListNodeWithSublist[] = list.options.filter(
    (style: OptionProps) => style.sublist,
  );
interface ListNodeWithSublist {
  label: string;
  value: string;
  sublist: ListProps;
}

I get error saying that OptionProps[] can’t be assigned to ListNodeWithSublist[] because sublist can’t be undefined. But since I filtered results to have only nodes with sublist, I think it would be right to assign array to ListNodeWithSublist. How to handle this?

This is, unfortunately, a limitation of TypeScript at the moment, see issue #42384, which is a suggestion for new behavior:

Typescript should be able to infer the type of an object, if a type guard was checked on a property of the said object. Currently, Typescript does correctly infer the type of the property, but not its parent object.

Until/unless that’s implemented, you can define your own type predicate instead:

function hasSublist(option: OptionProps): option is ListNodeWithSublist {
    return typeof option.sublist !== "undefined";
}

…and then use it in that code (it also means you can leave off the type annotation, since it’s inferred from the result of the filter):

const nodesWithSublist = list.options.filter(hasSublist);

Playground link

Leave a Comment