You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript函数式编程清洁架构项目错误排查求助

TypeScript函数式编程(fp-ts)两类类型错误修复方案

错误1:TaskEither<Error, void>无法赋值给TaskEither<Error, Option<User[]>>

原因分析

void类型通常来自以下场景:

  • 在TaskEither链式调用中使用map/chain时,内部函数未返回预期的Option<User[]>类型(比如函数无返回值、返回undefined)。
  • 调用了返回Promise<void>的异步函数,且未在链式操作中正确返回目标类型的结果。

修复示例

假设错误代码如下:

import { TaskEither, chain } from 'fp-ts/TaskEither';
import { Option } from 'fp-ts/Option';

type User = { id: number };

const saveAuditLog = async (): Promise<void> => { /* 记录日志的异步操作 */ };

// 错误写法:chain内部未返回正确的TaskEither类型
const fetchUsers: () => TaskEither<Error, Option<User[]>> = () => {
  return pipe(
    TaskEither.right(Option.some([{ id: 1 }])),
    chain(async (users) => {
      await saveAuditLog();
      // 此处未返回users,导致返回Promise<void>,最终类型变为TaskEither<Error, void>
    })
  );
};

修复后代码:

const fetchUsers: () => TaskEither<Error, Option<User[]>> = () => {
  return pipe(
    TaskEither.right(Option.some([{ id: 1 }])),
    chain(async (users) => {
      await saveAuditLog();
      // 必须返回正确的TaskEither<Error, Option<User[]>>类型
      return TaskEither.right(users);
    })
  );
};

如果是误用map导致的无返回值:

// 错误写法:map内部无返回值
const fetchUsers = pipe(
  TaskEither.right(Option.some([{ id: 1 }])),
  map(() => console.log('Fetched users')) // 返回void,类型变为TaskEither<Error, void>
);

// 修复:返回原Option<User[]>
const fetchUsers = pipe(
  TaskEither.right(Option.some([{ id: 1 }])),
  map((users) => {
    console.log('Fetched users');
    return users;
  })
);

错误2:(country: string) => TaskEither<Error, Option<User[]>>与(b: Either<DomainError, string>) => TaskEither<Error, Option<User[]>>不兼容

原因分析

Either是fp-ts库的核心类型,代表“要么成功值、要么错误值”的容器。错误根源是:链式调用(比如chain)中前一个TaskEither的右值是Either<DomainError, string>,但传入的函数只接受原始string类型,参数类型不匹配。

修复示例

假设错误代码如下:

import { TaskEither, chain } from 'fp-ts/TaskEither';
import { Either, right } from 'fp-ts/Either';
import { Option } from 'fp-ts/Option';

type DomainError = { type: 'InvalidCountry' };
type User = { id: number; country: string };

const fetchUsersByCountry = (country: string): TaskEither<Error, Option<User[]>> => {
  return TaskEither.right(Option.some([{ id: 1, country }]));
};

// 错误写法:chain期望函数参数是Either<DomainError, string>,但fetchUsersByCountry只接受string
const getUsers = () => {
  const validatedCountry: Either<DomainError, string> = right('US');
  return pipe(
    TaskEither.right(validatedCountry),
    chain(fetchUsersByCountry) // 类型不兼容
  );
};

修复方法1:在chain中处理Either的分支

const getUsers = (): TaskEither<Error, Option<User[]>> => {
  const validatedCountry: Either<DomainError, string> = right('US');
  return pipe(
    TaskEither.right(validatedCountry),
    chain((eitherCountry) => 
      eitherCountry.match(
        // 处理DomainError,转为Error类型的左值
        (err) => TaskEither.left(new Error(`Invalid country: ${err.type}`)),
        // 成功时调用原函数
        (country) => fetchUsersByCountry(country)
      )
    )
  );
};

修复方法2:先将Either转为TaskEither再链式调用

import { fromEither } from 'fp-ts/TaskEither';
import { chainW } from 'fp-ts/TaskEither';

const getUsers = (): TaskEither<Error, Option<User[]>> => {
  const validatedCountry: Either<DomainError, string> = right('US');
  return pipe(
    // 将Either转为TaskEither<DomainError, string>
    fromEither(validatedCountry),
    // 用chainW兼容错误类型(DomainError → Error)
    chainW(fetchUsersByCountry)
  );
};

内容的提问来源于stack exchange,提问作者user1790300

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 05:27:46