我尝试使用 fp-ts 函数编程库编写代码,但不断收到以下类型错误:
TS2322:类型未知不可分配给类型 TaskEither
问题是什么,因为我不确定错误告诉我问题是什么?
如何修复此错误?
任何帮助将不胜感激。
下面代码中突出显示的部分似乎是错误的来源:
const findByUserAndGroup = groupMemberRepository.findByUserAndGroup(cancelGroupMembershipDTO.groupId);
pipe(
sequenceS(ApplyPar)({
user: findByUserAndGroup(cancelGroupMembershipDTO.userId),
userToCancel: findByUserAndGroup(cancelGroupMembershipDTO.userToCancelId)
}),
chain(({ user, userToCancel }) =>
**pipe(
user,
isGroupOwner,
fromEither,
map(() => userToCancel)
)**
),
map((userToCancel) => ({
groupMemberId: userToCancel.groupMemberId,
groupId: userToCancel.groupId,
userId: userToCancel.userId,
isGroupOwner: userToCancel.isGroupOwner
})),
chain((processedDetails) => userRepo.delete(processedDetails))
)
按用户和组查找:
const findByUserAndGroup = (groupMemberId: string) => (userId: string): TaskEither<ErrorBase, Option<GroupMember>> => {
return pipe(
tryCatch(
() => pool.query(
`select *
from groupMember
where groupMemberId = ${groupMemberId} and userId = ${userId}
`
),
(error: any) => ({message: `Database error: ${String(error)}`, name: 'SystemError', details: 'Database Error.', innerError: error})
),
chain(result => right(none))
);
}
IsGroupOwner 验证函数:
export const isGroupOwner = (groupMember: GroupMember): TaskEither<ErrorBase, GroupMember> => {
if (!groupMember.isGroupOwner) {
return left({message: `You do not have the permissions necessary to perform this operation.`)});
}
return right(groupMember);
}
错误消息 Typeknown is not allocate to type
TaskEither<ErrorBase, unknown>
表明 TypeScript 期望特定的返回类型 (TaskEither<ErrorBase, unknown>
),但它却接收到未知的类型。
代码中的罪魁祸首很可能是由于
findByUserAndGroup
返回的 Option 类型造成的。当您从 findByUserAndGroup
返回包装在 TaskEither 中的 Option 时,它与您正在使用的功能链中的预期类型不直接匹配。当类型通过管道和链传递时,这种差异会导致问题。
要解决此问题,您需要正确处理 Option 类型,将其转换为
TaskEither
。以下是调整代码的方法:
正确处理选项类型:当
findByUserAndGroup
返回选项时,您应该将其映射到管道内的Either。如果Option为None,则返回错误(使用fp-ts
中的left);否则,继续使用 Some
值。
重构管道:您应该确保
isGroupOwner
接收到GroupMember
并且所有返回的类型都对齐为TaskEither<ErrorBase, GroupMember
>。
修改 isGroupOwner 用法:使用
fromOption
将 Option<GroupMember>
转换为管道内的 Either
。这将确保您在整个过程中获得一致的输入。
import { TaskEither, chain, map, left, right, fromEither } from 'fp-ts/TaskEither';
import { Option, fold as foldOption, some, none } from 'fp-ts/Option';
import { pipe } from 'fp-ts/function';
import { sequenceS } from 'fp-ts/Apply';
import { ApplyPar } from 'fp-ts/TaskEither';
import { fromOption } from 'fp-ts/Either';
import { ErrorBase } from './types'; // Assuming you have this type defined elsewhere
// Adjusted `findByUserAndGroup` function to match the expected types
const findByUserAndGroup = (groupMemberId: string) => (userId: string): TaskEither<ErrorBase, GroupMember> => {
return pipe(
tryCatch(
() => pool.query(
`select *
from groupMember
where groupMemberId = ${groupMemberId} and userId = ${userId}
`
),
(error: any) => ({ message: `Database error: ${String(error)}`, name: 'SystemError', details: 'Database Error.', innerError: error })
),
chain(result => {
// Assuming your query result parsing here to Option
const groupMemberOption = some(result.rows[0]); // Replace with actual parsing logic
return fromOption(() => ({ message: "Group member not found", name: "NotFoundError" }))(groupMemberOption);
})
);
};
// The `isGroupOwner` function remains the same
export const isGroupOwner = (groupMember: GroupMember): TaskEither<ErrorBase, GroupMember> => {
if (!groupMember.isGroupOwner) {
return left({ message: `You do not have the permissions necessary to perform this operation.` });
}
return right(groupMember);
};
// Main pipe function
const result = pipe(
sequenceS(ApplyPar)({
user: findByUserAndGroup(cancelGroupMembershipDTO.groupId)(cancelGroupMembershipDTO.userId),
userToCancel: findByUserAndGroup(cancelGroupMembershipDTO.groupId)(cancelGroupMembershipDTO.userToCancelId)
}),
chain(({ user, userToCancel }) =>
pipe(
user,
fromEither(() => ({ message: 'User not found', name: 'NotFoundError' })), // Convert `Option` to `Either`
chain(isGroupOwner), // Now `isGroupOwner` will work on `GroupMember`
map(() => userToCancel)
)
),
map((userToCancel) => ({
groupMemberId: userToCancel.groupMemberId,
groupId: userToCancel.groupId,
userId: userToCancel.userId,
isGroupOwner: userToCancel.isGroupOwner
})),
chain((processedDetails) => userRepo.delete(processedDetails))
);