[英]How to pipe and chain an operation that uses multiple `Eithers` and `Promises` from `fp-ts`
我是fp-ts
新手,我正在嘗試創建一個類似函數的方法:
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>>;
我想將這些驗證鏈接到 pipe 中,所以我嘗試通過以下方式實現驗證:
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
中執行所有這些操作
希望這能有所幫助。
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.map(validateUser), //validate token, returns TE.TaskEither<Error, TE.TaskEither<Error, void>>
TE.flatten, //To unwrap nested TaskEither<Error, void>
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 而不是 promises,但這應該不是問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.