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

使用fp-ts的sequenceS处理不同Left类型Either的类型推断问题

解决fp-ts中sequenceS无法自动推断Left联合类型的问题

当使用fp-ts的sequenceS函数处理多个不同Left类型的Either时,TypeScript无法自动将多个Left类型推断为联合类型,导致出现类型不兼容错误。

示例代码:

import * as E from 'fp-ts/Either'

type EmailValidationError = { type: 'EmailError' }
type UsernameValidationError = { type: 'UsernameError' }
type Email = string

declare function validateEmail(email: string): E.Either<EmailValidationError, Email>
declare function validateUsername(username: string): E.Either<UsernameValidationError, Email>

function validateData(inputs: { email: string; username: string }) {
  return E.sequenceS(E.Apply)({
    email: validateEmail(inputs.email),
    username: validateUsername(inputs.username),
  })
}

错误信息:

Type 'UsernameValidationError' is not assignable to type 'EmailValidationError'.

解决方案

1. 封装自动推断联合类型的sequenceS工具函数

封装通用工具函数,自动提取所有Either的Left类型并组成联合类型,无需手动指定:

import * as E from 'fp-ts/Either'

// 封装自动推断Left联合类型的sequenceS工具
const sequenceSEither = <T extends Record<string, E.Either<any, any>>>(validations: T) =>
  E.sequenceS(E.Apply)<
    T[keyof T] extends E.Either<infer L, any> ? L : never
  >()(validations) as E.Either<
    T[keyof T] extends E.Either<infer L, any> ? L : never,
    { [K in keyof T]: T[K] extends E.Either<any, infer R> ? R : never }
  >

// 使用工具函数
function validateData(inputs: { email: string; username: string }) {
  return sequenceSEither({
    email: validateEmail(inputs.email),
    username: validateUsername(inputs.username),
  })
}

2. 显式放宽Apply类型约束

通过将E.Apply的类型显式放宽,让TypeScript自动推断联合类型:

function validateData(inputs: { email: string; username: string }) {
  return E.sequenceS(E.Apply as E.Apply<E.Either<any, any>>)({
    email: validateEmail(inputs.email),
    username: validateUsername(inputs.username),
  })
}

3. 利用类型推断提取联合类型

先将验证结果存入变量,自动提取Left联合类型后传入sequenceS:

function validateData(inputs: { email: string; username: string }) {
  const validations = {
    email: validateEmail(inputs.email),
    username: validateUsername(inputs.username),
  }
  
  // 自动提取所有Left类型的联合
  type LeftErrors = typeof validations[keyof typeof validations] extends E.Either<infer L, any> ? L : never
  
  return E.sequenceS(E.Apply)<LeftErrors>(validations)
}

内容的提问来源于stack exchange,提问作者David Novák

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 03:42:46