Машинопись: Generi c Ограничение может быть вызвано разными подтипами - PullRequest
0 голосов
/ 05 августа 2020

Я пытаюсь написать общую функцию c карты, которая может работать с любыми Functor, которая выглядит так:

interface Functor<A> {
    map <B>(fn: (a: A) => B): Functor<B>;
    inspect (): string;
}

function map2<X, Y, F1 extends Functor<X>, F2 extends Functor<Y>> (fn: (a: X) => Y) {
    return function $map (functor: F1): F2 {
        return functor.map(fn);
    }
}

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

Type 'Functor<Y>' is not assignable to type 'F2'.
    'Functor<Y>' is assignable to the constraint of type 'F2', but 'F2' could be instantiated with a different subtype of constraint 'Functor<Y>'

Из того, что я понял после прочтения этого ответа, эта ошибка говорит мне, что после вызова functor.map(fn) я могу получить функтор, который не совпадает с тем, который был введен?

Если это так, как я могу записать это в принудительно выполнить это (например, я вставил Maybe<A>, я получил Maybe<B> вместо Either<B> или что-то в этом роде). Нужно ли мне переносить некоторые из этих ограничений в интерфейс Functor?

Если это не то, что происходит, что происходит и как я могу решить эту проблему?

1 Ответ

0 голосов
/ 05 августа 2020

быстро и грязно через кастинг

function map2<X, Y,
    F1 extends Functor<X>,
    F2 extends Functor<Y>
> (fn: (a: X) => Y) {
    return function $map (functor: F1): F2 {
        return <F2> functor.map(fn);
    }
}

другой кастинг фалавор

function map3<X, Y,
    F1 extends Functor<X>,
    F2 extends Functor<Y>
    > (fn: (a: X) => Y) {
    return function $map (functor: F1): F2 {
        return  functor.map(fn) as F2;
    }
}

или параметр упрощенного шаблона

type InferFunctorM<F> =  F extends Functor<infer As> ? As : never;


function map4<
    F1 extends Functor<any>,
    F2 extends Functor<any>
> (fn: (a: InferFunctorM<F1> ) => InferFunctorM<F2>) {
    return function $map (functor: F1): F2 {
        return <InferFunctorM<F2>> functor.map(fn);
    }
}

function map5<X, Y
    > (fn: (a: X) => Y) {
    return function $map (functor: Functor<X>): Functor<Y> {
        return  functor.map(fn);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...