В дальнейшем я буду использовать соглашения об именах параметров типа TS (заглавные буквы), и я везде изменил «succes» на «success». Это изменения cosmeti c, которые вы можете игнорировать, если хотите. Я придерживался соглашения о ссылках на типы «success» как A
и B
, и я буду ссылаться на типы «fail» как E
и F
. Я признаю, что F
не является хорошим названием для типа ошибки, но алфавит c, параллельный A
/ B
, был слишком заманчивым для меня, чтобы сопротивляться.
Основная проблема возможно, ваша функция then()
и функция railRoad()
не имеют понятия расширения типа ошибки. Вот один из способов сделать это с помощью then()
:
const then = <A, B, F>(f: fun<A, Result<B, F>>) => <E>(r: Result<A, E>) =>
join(map<A, Result<B, E | F>, E>(f)(r))
Здесь начальная функция берет что-то, что превращает A
в Result<B, F>
, а затем принимает Result<A, E>
и производит Result<B, E | F>
. Это объединение E
и F
в E | F
является ключевым компонентом для того, чтобы ваши выводы работали позже.
Вторая проблема заключается в том, что ваша функция railRoad()
использует поддержка логических типов c высшего порядка добавлена в TypeScript 3.4, но конкретная формулировка приводит к довольно низкой производительности компилятора. Предполагаемый тип функции является рекурсивным типом типа {map: () => {map: () => ....
. Чтобы предотвратить это, я создал интерфейс RailRoaded<A, E>
для представления возвращаемого типа railRoad()
:
interface RailRoaded<A, E> {
map<B>(f: (some: A) => B): RailRoaded<B, E>;
then<B, F>(f: (some: A) => Result<B, F>): RailRoaded<B, E | F>;
}
const railRoad = <A, E>(r: Result<A, E>): RailRoaded<A, E> => ({
map: <B>(f: (some: A) => B) => railRoad<B, E>(map<A, B, E>(f)(r)),
then: <B, F>(f: (some: A) => Result<B, F>) => railRoad(then(f)(r))
})
Аннотирование возвращаемого типа railRoad
как RailRoaded<A, E>
значительно повышает производительность, поскольку компилятор имеет только проверить , что функция совместима и не пытается синтезировать для нее новый тип возвращаемого значения. В любом случае вы также можете увидеть, как метод then()
для RailRoaded<A, E>
генерирует тип ошибки объединенного типа.
Вот и все. Вот что происходит, когда вы называете это:
const chooChoo = railRoad(getUser()).then(formatName).map(greet);
// const chooChoo: RailRoaded<string, "no-user" | "no-name">
Выглядит хорошо, я думаю. Просто чтобы быть уверенным, давайте разберем это, чтобы увидеть выводы для каждого шага:
const engine = railRoad(getUser());
// const engine: RailRoaded<User, "no-user">
const car = engine.then(formatName);
// const car: RailRoaded<string, "no-user" | "no-name">
const caboose = car.map(greet);
// const caboose: RailRoaded<string, "no-user" | "no-name">
Также хорошо. Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код