typescript 如何从'fp-ts'中管道化和链接使用多个'Either'和'Promises`的操作

g52tjvyc  于 2022-12-30  发布在  TypeScript
关注(0)|答案(1)|浏览(99)

我是fp-ts的新手,我正在尝试创建一个类似函数的方法,它:
1.解析承载令牌
1.使用解析的令牌检查用户是否有效

import { Request } from 'express';
import { either } from 'fp-ts';
import { pipe } from 'fp-ts/lib/function';

// * Parse the token
declare const parseRawToken: (rawToken: string | undefined) => either.Either<Error, string>;

// * Interface of the validate method
type MakeIsRequestAuthenticated = (
  validateUserWithToken: (data: string) => Promise<either.Either<Error, void>>,
) => (request: Request) => Promise<either.Either<Error, void>>;

我想将这些验证链接到一个管道中,所以我尝试通过以下方式实现验证:

export const makeIsRequestAuthenticated: MakeIsRequestAuthenticated = validateUserWithToken => {
  // * Validate the request
  return async request => {
    return pipe(
      parseRawToken(request.header('Authorization')),
      either.chain(validateUserWithToken)
      );
  };
};

但它给出了以下错误:

Argument of type '(data: string) => Promise<Either<Error, void>>' is not assignable to parameter of type '(a: string) => Either<Error, void>'.
  Type 'Promise<Either<Error, void>>' is not assignable to type 'Either<Error, void>'.ts(2345)

我试过用TaskEither和其他一些解决方案替换Promise,但都不起作用
我希望使用chain或其他一些方法,以便能够在pipe中执行所有这些操作

ia2d9nvy

ia2d9nvy1#

希望这能有所帮助:

  • 我稍微修改了validate方法的接口以返回请求,允许另一个处理程序接收请求并在验证之后执行任何操作
  • 我修改了validateUserWithToken的接口,以返回TaskEither〈Error,void〉而不是promise。
import { Request } from 'express';
import { pipe } from 'fp-ts/lib/function';
import * as TE from "fp-ts/TaskEither";
import * as E from "fp-ts/Either";
import { assert } from 'console';

// * Parse the token (dummy implementation)
const parseRawToken = (rawToken: string | undefined) =>
    rawToken ? E.right(rawToken) : E.left(new Error("Invalid token"));

// * Interface of the validate method (changed return type to TastEither<Error, Request>)
type MakeIsRequestAuthenticated = (
    validateUserWithToken: (data: string) => TE.TaskEither<Error, void>,
) => (request: Request) => TE.TaskEither<Error, Request>;

//Actual implementation
export const makeIsRequestAuthenticated: MakeIsRequestAuthenticated =
    validateUser => (request: Request) =>
        pipe(
            request.header("Authorization"), //returns string | undefined
            parseRawToken, //returns  Either<Error, string>
            TE.fromEither, //To TaskEither
            TE.chain(validateUser), //validate token 
            TE.map(() => request) //If no errors return request
        )

//Mock request
const mockRequest = {
    header: (name: string) => "fake token",
    body: {
        userName: "MsFake",
    }
} as Request;

//Dummy implementations for tokenValidators: sucess and fail
const mockValidToken: (token: string) => TE.TaskEither<Error, void> =
    (token: string) => TE.right(void 0);
const mockInValidToken: (token: string) => TE.TaskEither<Error, void> =
    (token: string) => TE.left(new Error("Token not valid"));

//Test
const fail = makeIsRequestAuthenticated(mockInValidToken)(mockRequest);
const sucess = makeIsRequestAuthenticated(mockValidToken)(mockRequest);

sucess().then(d => assert(d._tag === "Right"));
fail().then(d => assert(d._tag === "Left"));

现在方法MakeIsRequestAuthenticated返回一个TaskEither<Error, Request>,你可以把它和任何一个以Request为参数的方法链接起来,从现在开始你可以用taskEither代替promise,但这应该不是问题。

相关问题