[英]convert or filter a `Task` from `Some` to `Left` with `fp-ts`
I'm trying to learn how to use type guards and predicted functions with io-ts
|我正在尝试学习如何在
io-ts
| 中使用类型保护和预测函数fp-ts
, and what I need to do the following: fp-ts
,以及我需要执行以下操作:
I've this function:我有这个 function:
createOne: ({ password, ...creatableUser }: CreatableUser): taskEither.TaskEither<ExceptionError, User> => {
....
}
And it'll need to:它需要:
// * Doubt Function
export const createOne = ({ password, ...creatableUserData }: CreatableUser): taskEither.TaskEither<Error, User> => {
// Generate the new user
const newUser: User = {
...creatableUserData,
id: randomUUID(),
};
return pipe(
// * Check that the user doesn't exists yet
creatableUserData.email,
findByEmail,
taskEither.fromTaskOption(() => new Error('User already exists')), // TODO: need to return a error on `Some`
// * Save the new `User` on the repository
taskEither.chain(() => save(newUser, password)),
// * Send the confirmation email to the user
taskEither.chain(() =>
sendMail({
body: 'Welcome to App Team',
}),
),
taskEither.map(() => newUser),
);
};
I need to 'parse' the response from taskOption.Some
to a taskEither.Left
, but i don't find a way to do that我需要“解析”从
taskOption.Some
到taskEither.Left
的响应,但我找不到这样做的方法
Here the types for a better context:这里的类型以获得更好的上下文:
import { randomUUID } from 'crypto';
import { TaskOption } from 'fp-ts/lib/TaskOption';
import { taskEither } from 'fp-ts';
import { TaskEither } from 'fp-ts/lib/TaskEither';
import { pipe } from 'fp-ts/lib/function';
// * Types for context
type CreatableUser = {
password: string;
email: string;
//...
}
type User = {
email: string;
id: string;
//...
}
declare const findByEmail: (email: string) => TaskOption<User>;
declare const save: (user: User, password: string) => TaskEither<Error, void>;
declare const sendMail: (message: {body: string}) => TaskEither<Error, void>;
Someone has some idea to how do filter or use a predicted function do early return if the user already exists?如果用户已经存在,有人知道如何过滤或使用预测的 function 提前返回?
I was able to fix this issue with the following code:我能够使用以下代码解决此问题:
export const makeCreateOne =
(usersRepository: UsersRepository, mailProvider: MailProvider) =>
({ password, ...creatableUserData }: CreatableUser): TaskEither<ExceptionError, User> => {
// Generate the new user
const newUser: User = {
...creatableUserData,
id: randomUUID(),
};
return pipe(
// * Get the user with the given email
creatableUserData.email,
usersRepository.findByEmail,
// * Return `null` if `Some`
TO.match(
// TODO: improve that
// None: The user doesn't exists, we can create a new user
() => true,
// Some: The user already exists, so we don't wanna keep the creation process
() => null,
),
TE.fromNullable(createExceptionError('User already exists', REQUEST_STATUS.not_found)),
// * Save the new `User` on the repository
TE.chain(() => usersRepository.save(newUser, password)),
// * Send the confirmation email to the user
TE.chain(() =>
mailProvider.sendMail({
body: 'Welcome to App Team',
}),
),
TE.map(() => newUser),
);
};
But still, doesn't look great, if someone had some idea to how to improve I appreciate但是,看起来仍然不太好,如果有人知道如何改进我很感激
If someone had the same doubt, here my solution: I figure out that at this point makes sense to create a method just to validate if the email is available, so I create this interface:如果有人有同样的疑问,这里是我的解决方案:我发现此时创建一个方法来验证 email 是否可用是有意义的,所以我创建了这个接口:
export type UsersRepository = {
readonly findByEmail: (email: string) => TaskOption<User>;
readonly findByID: (id: string) => TaskOption<User>;
readonly save: (user: User, password: string) => TaskEither<ExceptionError, void>;
readonly update: (user: User, password?: string) => TaskEither<ExceptionError, void>;
readonly delete: (userID: ID) => TaskEither<ExceptionError, void>;
readonly all: () => TaskEither<ExceptionError, ReadonlyArray<User>>;
readonly isUserPasswordValid: (email: string, password: string) => Task<boolean>;
readonly isEmailAvailable: (email: string) => Task<Boolean>;
};
And refactor the function to works like:并将 function 重构为:
export const makeCreateOne =
(usersRepository: UsersRepository, mailProvider: MailProvider) =>
({ password, ...creatableUserData }: CreatableUser): TaskEither<ExceptionError, User> => {
// Generate the new user
const newUser: User = {
...creatableUserData,
id: randomUUID(),
};
return pipe(
// * Get the user with the given email
creatableUserData.email,
usersRepository.isEmailAvailable,
TE.fromTask,
TE.filterOrElse(
isEmailAvailable => isEmailAvailable,
() => createExceptionError('Check your password and try again', REQUEST_STATUS.bad),
),
// * Save the new `User` on the repository
TE.chain(() => usersRepository.save(newUser, password)),
// * Send the confirmation email to the user
TE.chain(() =>
mailProvider.sendMail({
body: 'Welcome to App Team',
}),
),
TE.map(() => newUser),
);
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.