как я могу использовать универсальный тип в теле функции

я пытаюсь инкапсулировать некоторую логику внутри компонента OrderGuard (который может работать с двумя типами заказов: CheckinOrder | Checkout order, но, когда я пытаюсь передать заказ обратному вызову orderLoad, машинописный текст начинает жаловаться так

CheckinOrder может быть назначен ограничению типа T, но экземпляр T может быть создан с другим подтипом constaint «Order».

type Order = CheckoutOrder | CheckinOrder;

interface Props<T extends Order> {
    orderId: string;
    orderLoaded: boolean;
    onOrderLoad: (order: T) => void;
    loadOrder: UseCheckinOrder | UseCheckoutOrder;
    children?: React.ReactElement;
}

const isCheckinOrder = (order: Order): order is CheckinOrder => {
    return !('servicesFallbackURL' in order);
};

const OrderGuard: <T extends Order>(props: Props<T>) => React.ReactElement<Props<T>> = ({
    orderId,
    orderLoaded,
    onOrderLoad,
    loadOrder,
    children
}) => {
    const [userHasAccess, setUserHasAccess] = useState(true);
    const { refetch, loading } = loadOrder(orderId, { skip: true });

    const handleOrderLoad = (order: Order) => {
        if (isCheckinOrder(order)) {
            onOrderLoad(order as CheckinOrder); // <-- error here
        } else {
            onOrderLoad(order as CheckoutOrder); // <-- and here
        }
    };

я думаю, что что-то упустил, но не могу понять, что я новичок в машинописном тексте, как другие справляются с такими ситуациями?

вызов компонента выглядит так

    <OrderGuard<CheckoutOrder>
        orderId={orderId}
        orderLoaded={!!order}
        onOrderLoad={fillOrder}
        loadOrder={useOrder}
    >
        <Checkout startNewSearch={startNewSearch} />
    </OrderGuard>

person Евгений Литвиненко    schedule 14.11.2019    source источник
comment
Релевантно: stackoverflow.com/q/56505560/251311   -  person zerkms    schedule 14.11.2019
comment
Разве вы не можете просто использовать const handleOrderLoad = (order: T) => onOrderLoad(order) или просто использовать onOrderLoad вместо handleOrderLoad (что ничего не делает в приведенном выше примере, но делегирует onOrderLoad)   -  person Aleksey L.    schedule 14.11.2019
comment
как другие справляются с этой ситуацией? --- в данном случае ваш OrderGuard не является общим. Просто объявите его как const OrderGuard = (props: Props<Order>), и, я думаю, все будет в порядке.   -  person zerkms    schedule 14.11.2019
comment
@АлексейЛ. нет, я получаю ту же ошибку, когда пытаюсь передать заказ в функцию onOrderLoad dropmefiles.com/SFio7   -  person Евгений Литвиненко    schedule 14.11.2019
comment
В этом утверждении типа нет необходимости, так как вы уже поместили перед ним функцию защиты типа.   -  person hackape    schedule 14.11.2019


Ответы (1)


Если не сделать интерфейс Prop универсальным, это решит вашу проблему в этом случае.

type Order = CheckoutOrder | CheckinOrder;

interface Props {
    orderId: string;
    orderLoaded: boolean;
    onOrderLoad: (order: Order) => void;
    loadOrder: UseCheckinOrder | UseCheckoutOrder;
    children?: React.ReactElement;
}

const isCheckinOrder = (order: Order): order is CheckinOrder => {
    return !('servicesFallbackURL' in order);
};

const OrderGuard: (props: Props) => React.ReactElement<Props> = ({
    orderId,
    orderLoaded,
    onOrderLoad,
    loadOrder,
    children
}) => {
    const [userHasAccess, setUserHasAccess] = useState(true);
    const { refetch, loading } = loadOrder(orderId, { skip: true });

    const handleOrderLoad = (order: Order) => {
        if (isCheckinOrder(order)) {
            onOrderLoad(order); // <-- no need to cast
        } else {
            onOrderLoad(order as CheckoutOrder); // <-- no more errors
        }
    };
person FunkeyFlo    schedule 14.11.2019