Машинопись не может сузить размеченное объединение

Допустим, у меня есть два типа: X и Y

type X = 'foo';
type Y = 'bar';

И у меня есть следующий дискриминированный союз:

type DiscriminatedUnion =
    | {
        type: 'X',
        fn: (arg: X) => void;
        arg: X;
    }
    | {
        type: 'Y',
        fn: (arg: Y) => void;
        arg: Y;
    }

Итак, ясно, что этот объект типа DiscriminatedUnion будет иметь как fn, так и arg одного типа: либо X, либо Y. Почему TS не может скомпилировать следующую функцию?

function acceptsUnion(union: DiscriminatedUnion): void {
    // it's obvious, that both fn and arg would be either X, or Y, but strictly the same type
    const {fn, arg} = union;
    fn(arg); // TS Error: Argument of type 'string' is not assignable to parameter of type 'never'. Type 'string' is not assignable to type 'never'
}

person Андрей Фирсов    schedule 24.06.2021    source источник
comment
Отвечает ли это на ваш вопрос? Почему объединение кортежей ожидает `never` as`. includes () `аргумент?   -  person captain-yossarian    schedule 24.06.2021
comment
Здесь catchts.com/react-props вы можете найти способ справиться с этим.   -  person captain-yossarian    schedule 24.06.2021


Ответы (1)


Я считаю, что этот вопрос является дубликатом этого Тем не менее я решил предложить решение.

Есть еще один способ, о котором я не упоминал в своем блоге.

Вы можете перегрузить свою функцию в объединении и добавить дополнительный общий. AFAIK, я преобразовал аргумент контравариантности в ковариантный. Не стесняйтесь критиковать меня

type DiscriminatedUnion =
    | {
        type: 'X',
        fn: (<T extends X|Y>(arg: T) => void) & (<T extends X>(arg: T) => void);
        arg: X;
    }
    | {
        type: 'Y',
        fn: (<T extends X|Y>(arg: T) => void) & (<T extends Y>(arg: T) => void);
        arg: Y;
    }
person captain-yossarian    schedule 24.06.2021