首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在FP-TS中连锁依赖TaskEither操作

如何在FP-TS中连锁依赖TaskEither操作
EN

Stack Overflow用户
提问于 2019-08-01 20:55:13
回答 1查看 5.7K关注 0票数 5

我刚接触过FP-TS,仍然不太了解如何使用TaskEither。我试图异步读取一个文件,然后用yaml解析承诺解析结果字符串。

==EDIT==

我用文件的全部内容更新了代码,以提供更多的上下文,并应用了MnZrK提供的一些建议。对不起,我仍然是新的FP-TS,我仍然在努力使类型匹配。

现在,我的错误是map(printConfig)行:

代码语言:javascript
复制
Argument of type '<E>(fa: TaskEither<E, AppConfig>) => TaskEither<E, AppConfig>' is not assignable to parameter of type '(a: TaskEither<unknown, AppConfig>) => Either<unknown, Task<any>>'.
  Type 'TaskEither<unknown, AppConfig>' is not assignable to type 'Either<unknown, Task<any>>'.
    Type 'TaskEither<unknown, AppConfig>' is missing the following properties from type 'Right<Task<any>>': _tag, rightts(2345)

我通过使用来自getOrElse的TaskEither而不是任何一个库来解决这个问题。

==END EDIT==

我已经成功地用IOEither作为一个同步操作执行了这个项目:sync-example

我还看过这里的示例代码:https://gcanti.github.io/fp-ts/recipes/async.html

完整代码在这里:async-example

代码语言:javascript
复制
import { pipe } from 'fp-ts/lib/pipeable'
import { TaskEither, tryCatch, chain, map, getOrElse } from "fp-ts/lib/TaskEither";
import * as T from 'fp-ts/lib/Task';
import { promises as fsPromises } from 'fs';
const yamlPromise = require('js-yaml-promise');

// const path = require('path');
export interface AppConfig {
  service: {
    interface: string
    port: number
  };
}

function readFileAsyncAsTaskEither(path: string): TaskEither<unknown, string> {
  return tryCatch(() => fsPromises.readFile(path, 'utf8'), e => e)
}

function readYamlAsTaskEither(content: string): TaskEither<unknown, AppConfig> {
  return tryCatch(() => yamlPromise.safeLoad(content), e => e)
}

// function getConf(filePath:string){
//   return pipe(
//       readFileAsyncAsTaskEither(filePath)()).then(
//           file=>pipe(file,foldE(
//               e=>left(e),
//               r=>right(readYamlAsTaskEither(r)().then(yaml=>
//                   pipe(yaml,foldE(
//                       e=>left(e),
//                       c=>right(c)
//                   ))
//               ).catch(e=>left(e)))
//           ))
//       ).catch(e=>left(e))
// }

function getConf(filePath: string): TaskEither<unknown, AppConfig> {
  return pipe(
    readFileAsyncAsTaskEither(filePath),
    chain(readYamlAsTaskEither)
  )
}

function printConfig(config: AppConfig): AppConfig {
  console.log("AppConfig is: ", config);
  return config;
}

async function main(filePath: string): Promise<void> {
  const program: T.Task<void> = pipe(
    getConf(filePath),
    map(printConfig),
    getOrElse(e => {
      return T.of(undefined);
    })
  );

  await program();
}

main('./app-config.yaml')

结果输出为:{ _tag: 'Right', right: Promise { <pending> } }

但是我想要结果AppConfig:{ service: { interface: '127.0.0.1', port: 9090 } }

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-08-02 13:56:05

所有这些e=>left(e).catch(e=>left(e))都是不必要的。你的第二种方法比较惯用。

代码语言:javascript
复制
// convert nodejs-callback-style function to function returning TaskEither
const readFile = taskify(fs.readFile);
// I don't think there is `taskify` alternative for Promise-returning functions but you can write it yourself quite easily
const readYamlAsTaskEither = r => tryCatch(() => readYaml(r), e => e);

function getConf(filePath: string): TaskEither<unknown, AppConfig> {
  return pipe(
    readFile(path.resolve(filePath)),
    chain(readYamlAsTaskEither)
  );
}

现在,您的getConf返回TaskEither<unknown, AppConfig>,它实际上是一个() => Promise<Either<unknown, AppConfig>>。如果您有比unknown更特定的错误类型,那么请使用它。

为了“解压”实际值,需要有一些主入口点函数,在该函数中使用mapchain组合配置所需的其他内容(即将其打印到控制台),然后应用一些错误处理来消除Either部件,最后只获取Task (实际上是懒惰的() => Promise):

代码语言:javascript
复制
import * as T from 'fp-ts/lib/Task';

function printConfig(config: AppConfig): AppConfig {
  console.log("AppConfig is", config);
  return config;
}

function doSomethingElseWithYourConfig(config: AppConfig): TaskEither<unknown, void> {
  // ...
}

async function main(filePath: string): Promise<void> {
  const program: T.Task<void> = pipe(
    getConf(filePath),
    map(printConfig),
    chain(doSomethingElseWithYourConfig),
    // getting rid of `Either` by using `getOrElse` or `fold`
    getOrElse(e => {
      // error handling (putting it to the console, sending to sentry.io, whatever is needed for you app)
      // ...
      return T.of(undefined);
    })
  );

  await program();
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57316857

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档