Возврат универсального типа не принимает объект, содержащий те же определенные поля - PullRequest
0 голосов
/ 04 июля 2019

Я пытаюсь написать функцию, которая принимает общий объект типа дерева, состоящий из узла типа children, который, в свою очередь, может необязательно иметь свои собственные children, второй аргумент - функция predicate с посещенным в данный момент узлом для передачи его в функцию фильтра.

Меня не волнуют дополнительные свойства внутри tree (за исключением children) и node подобных объектов.По этой причине я решил реализовать эту функцию с использованием обобщений.Ниже приведена упрощенная версия моего кода.

interface NodeLike {
    children?: NodeLike[];
}

interface TreeLike {
    children: NodeLike[];
}

export function filterChildrenFromTree<T extends TreeLike, N extends NodeLike>(
    t: T,
    predicate: (n: N) => boolean
): T {
    const newTree = {
        children: t.children.filter(predicate)
    };

    return newTree;
}

К сожалению, машинопись дает мне следующую ошибку в строке return:

Type '{ children: NodeLike[]; }' is not assignable to type 'T'.

Если указать, что T в этом случаерасширяет объект TreeLike, почему машинопись выдает сообщение, когда я возвращаю объект в ожидаемом формате?

Ответы [ 2 ]

2 голосов
/ 04 июля 2019

T расширяет TreeLike, но TreeLike не расширяет T. Код пытается вернуть TreeLike вместо T.

Тип newTree должен быть T, но это '{children: NodeLike []; }».

Самое простое исправление

const newTree = {
    ...t, 
    children: t.children.filter(predicate)
};
0 голосов
/ 04 июля 2019

Возможно, я неправильно понял, что вы хотите, но для меня более общим подходом может быть описание абстракции вашего дерева в функциональных терминах, а не как известное свойство children на каждом узле. Вы можете определить следующие типы функций, представляющие необязательную природу потомков с типом T[]|undefined, но здесь я выбрал пустой массив для представления той же ситуации, поскольку он упрощает логику:

type ChildSelector<T> = (item: T) => T[];
type Pred<T> = (item: T, index: number) => boolean;
type TreeAssembler<T> = (children: T[]) => T;

Теперь это позволяет вам написать функцию фильтрации, которая не имеет ограничений по типу дерева, которое можно фильтровать

export function filterChildrenFromTree<T>(
  t: T,
  childSelector: ChildSelector<T>,
  predicate: Pred<T>,
  treeAssembler: TreeAssembler<T>
): T {
  const children = childSelector(t);
  const newTree = treeAssembler(children.filter(predicate));
  return newTree;
}
...