Typescript array.map неправильно распределяет типы пересечений - PullRequest
1 голос
/ 19 февраля 2020

У меня есть массив типа object[] & Tree[], но arr.map(child => ...) выводит тип потомка как object, а не object & Tree.

Есть ли способ избежать этого без дополнительного приведения?

В частности, Tree расширяет object, но машинописный текст, похоже, не осознает этого и объединяет две части типа пересечения.

EDIT - Минимальный воспроизводимый пример:

Это надумано, но основано на моем другом недавнем вопросе Преобразование типа объекта машинописного текста в сопоставленный тип, который ссылается на себя

interface BasicInterface {
    name: string;
    children: object[];
}

function getBasic<T extends object>(input: T): BasicInterface {
    return input as BasicInterface;
}

export const basicTree = getBasic({
    name: 'parent',
    children: [{
        name: 'child',
        children: []
    }]
});

Дело в том, что приведенный ниже код имеет доступ к "basicTree" и его предполагаемый тип. Для этого примера я определил BasicInterface, но на практике это генерируется автоматически, и я не нашел способа программно сгенерировать рекурсивный интерфейс.

Я хотел бы добавить рекурсивный тип потомков обратно в качестве исходного Интерфейс определяет.

Вместо того, чтобы полностью переопределить BasicInterface в коде, поскольку это может быть много шаблонного, я пытаюсь «улучшить» определение типа basicTree с помощью правильного рекурсивного определения.

Но это падает при получении типа детей. Возможно, есть более простое решение?

type RestoredInterface = typeof basicTree & {
    children: RestoredInterface[]
};

function getTree(basic: BasicInterface): RestoredInterface {
    return basic as RestoredInterface;
}

const restoredTree = getTree(basicTree);

const names = restoredTree.children.map(child => child.name);

Ответы [ 2 ]

1 голос
/ 20 февраля 2020

Я нашел странное решение. Просто измените порядок в объявлении. Это странно, но работает:

type RestoredInterface = {
    children: RestoredInterface[]
} & typeof basicTree;

Редактировать: Вот объяснение .

Лучшее решение может быть примерно таким:

type RestoredInterface = Omit<typeof basicTree, 'children'> & {
    children: RestoredInterface[]
};

См. Детская площадка

0 голосов
/ 20 февраля 2020

Основываясь на наблюдении от jcalz, на самом деле можно просто расширить оригинальный интерфейс. Я был сбит с толку, потому что он определен программно, но это не проблема, если вы назовете его первым:

type BasicTreeInterface = typeof basicTree;

interface RestoredInterface extends BasicTreeInterface {
    children: RestoredInterface[]
};

const restoredTree = getTree(basicTree);

const names = restoredTree.children.map(child => {
    // Child is of type RestoredInterface
});
...