Typescript fp ts:我该怎么做;“向上拉”;是否将嵌套的`other`/`taskother`添加到外部类型?
我正在学习一些Typescript fp ts:我该怎么做;“向上拉”;是否将嵌套的`other`/`taskother`添加到外部类型?,typescript,fp-ts,Typescript,Fp Ts,我正在学习一些fp-ts。要创建我遇到的问题的样式化版本,假设我想要创建一个不存在的表,所以我必须查询数据库:一个容易出错的异步操作。如果该表不存在,我想创建它:另一个容易出错的异步操作。进一步假设错误类型都是字符串(尽管我还想知道如何在需要时创建union错误类型),并且成功创建时返回的值是数字ID 简言之,查看表是否存在,如果不存在,则在创建过程中可能会出现错误。关键是我希望这两个错误都反映在最外层的类型中:atask或。问题是我不知道如何避免获得任务。也就是说,我不知道如何将选项中的错误向
fp-ts
。要创建我遇到的问题的样式化版本,假设我想要创建一个不存在的表,所以我必须查询数据库:一个容易出错的异步操作。如果该表不存在,我想创建它:另一个容易出错的异步操作。进一步假设错误类型都是字符串(尽管我还想知道如何在需要时创建union错误类型),并且成功创建时返回的值是数字ID
简言之,查看表是否存在,如果不存在,则在创建过程中可能会出现错误。关键是我希望这两个错误都反映在最外层的类型中:atask或
。问题是我不知道如何避免获得任务。也就是说,我不知道如何将选项中的错误向上拉,并将其合并到最外层的错误中
(也许这涉及序列或可遍历项?我仍在学习这些。)
关于某些代码:
从“fp ts”导入{task或作为TE,选项作为O};
从“fp ts/lib/function”导入{pipe};
//tableExists:()=>TE.task
//createTable:()=>TE.tasktable
//我希望这能代表两种可能的错误。当前存在类型错误。
//------------------------------------VV
常量示例=():TE.taskOrther=>{
回流管(
tableExists(),
//如何将可能的“left”向上拉至最外层类型?
//---------------------------------------VVVVVV
TE.map((存在)=>(存在?O.none:O.some(createTable())
);
};
我相信我已经解决了这个问题,当然欢迎任何更正
我认为我需要将选项
向下“推”到嵌套的任务
中,而不是将任务
从选项
中向上“拉”,以便嵌套将任务
的层彼此相邻,允许通过链
将它们展平
const-example=():TE.taskOrther=>
烟斗(
tableExists(),
TE.链((存在)=>
存在
?测试结果(无)
:管道(
createTable(),
TE.地图(O.of)
)
)
);
如果错误类型不同,我会怎么做的附带问题似乎也由此代码处理,除了TE.chainW
替换TE.chain
似乎是您自己解决的:)如果有帮助,我已经将这个示例实现为一个有区别的联合,这样您就可以很容易地识别调用example
时发生的错误
import * as TE from 'fp-ts/lib/TaskEither'
import * as O from 'fp-ts/lib/Option'
import { pipe } from "fp-ts/lib/function";
declare const tableExists: () => TE.TaskEither<string, boolean>
declare const createTable: () => TE.TaskEither<string, number>
// Discriminated union so you can easily identify which error it is
type ExampleErr = { tag: "TableExistsError", error: unknown } | { tag: "CreateTableError", error: unknown }
const example = (): TE.TaskEither<ExampleErr, O.Option<number>> => {
return pipe(
tableExists(),
TE.mapLeft(error => ({ tag: "TableExistsError" as const, error })),
TE.chainW(exists => exists ?
TE.right(O.none) :
pipe(
createTable(),
TE.mapLeft(error => ({ tag: "CreateTableError" as const, error })),
TE.map(O.some)
)
)
);
};
import*as TE from'fp ts/lib/taskother'
从“fp ts/lib/Option”以O形式导入*
从“fp ts/lib/function”导入{pipe};
declare const tableExists:()=>TE.task
声明const createTable:()=>TE.tasktable
//有区别的联合,因此您可以轻松确定它是哪个错误
键入ExampleErr={tag:“TableExistError”,错误:未知}{tag:“CreateTableError”,错误:未知}
常量示例=():TE.taskOrther=>{
回流管(
tableExists(),
mapLeft(error=>({tag:“TableExistError”作为常量,error})),
TE.chainW(exists=>exists?
TE.右(无):
烟斗(
createTable(),
mapLeft(error=>({tag:“CreateTableError”作为常量,error})),
特图(O.some)
)
)
);
};
如果table存在和createTable
中的错误类型不同,您已正确识别需要使用chainW
。fp ts
中函数末尾的W
表示“加宽”,通常允许类型加宽到两种类型的并集。对于taskorth
的chainW
,这意味着错误类型将成为两种taskorth
类型的并集(进入chainW
的类型和在其中返回的类型)
理解何时使用map
以及何时使用chain
是一个基本概念,这对于理解好非常重要map
允许您修改结构中的值,这是a->B
中的一个简单函数<代码>链
允许您根据第一个效果执行另一个效果-因此您必须返回一个值,该值与处理的效果相同。在本例中,您使用的是tasktory
,因此传递给chain
的函数也需要是A->tasktory
类型(其中createTable
是,但是您还需要手动处理表已经存在的情况,并使用TE.right(O.none)在那里构建tasktory)
或TE.of(O.none)
。有道理,谢谢!我知道有点生锈,在这里看到相同或相似的概念很有趣(map
;和_-then
/chain
;等等)。虽然我还没有完全掌握单子、函子、应用程序等的理论,但我通过这些语言/库结构将这些理论付诸实践,从实践的角度理解了它们的价值和用途。很酷的东西!