首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在TypeScript中是否有一种更简洁的表达许多嵌套映射函数的方法?

在TypeScript中是否有一种更简洁的表达许多嵌套映射函数的方法?
EN

Stack Overflow用户
提问于 2021-05-13 18:41:38
回答 1查看 402关注 0票数 1

考虑到下面的代码,在TypeScript中是否有更简洁的方法来表达许多嵌套的映射函数?对于这个用例,我喜欢Scala的“理解”,但是我在TypeScript中找不到相应的。我觉得我错过了一些很明显的东西。

由于验证原因,我有几个对象可能无法实例化,所以返回类型都是Either<string, T>。例如:

代码语言:javascript
复制
const userId: Either<string, UserId> = UserId.create('1234')

当组合由上面的许多语句组成的对象时,很难看到。为了提高可读性,示例中的所有变量都被替换为字符串。

In TypeScript,,这就是我要做的。有没有更干净的方式来表达这一点而不失去我的类型?

代码语言:javascript
复制
const userSettings: Either<string, UserSettings> = UserId.create('1234').chain(userId => {
  return Email.create('hello@world.com').chain(email => {
    return Active.create(183).chain(active => {
      return Role.create('admin').map(role => {
        return UserSettings(userId, email, active, role)
      })
    })
  })
})

在Scala中,我可以这样表示上面的代码:

代码语言:javascript
复制
for {
  userId <- UserId.create('1234')
  email  <- Email.create('hello@world.com')
  active <- Active.create(183)
  role   <- Role.create('admin')
} yield UserSettings(userId, email, active, role)

我正在使用净化库进行类型设置,比如。

有谁有任何技巧、建议和/或库可以帮助清理我嵌套的映射函数TypeScript混乱呢?

EN

回答 1

Stack Overflow用户

发布于 2021-08-22 03:39:32

你可以用这样的东西:

代码语言:javascript
复制
const userSettings = Right({})
  .chain(acc => UserId.create('1234').map(userId => ({...acc, userId})))
  .chain(acc => Email.create('hello@world.com').map(email => ({...acc, email})))
  .chain(acc => Active.create(183).map(active => ({...acc, active})))
  .chain(acc => Role.create('admin').map(role => ({...acc, role})))
  .map(({userId, email, active, role}) => UserSettings(userId, email, active, role))

您还可以定义一个助手函数:

代码语言:javascript
复制
// This implementation works for all functors, but the types only work for
// Either due to TypeScript's lack of HKTs
const bind =
  <N extends string, A extends object, L, R>(
    name: Exclude<N, keyof A>,
    f: (acc: A) => Either<L, R>
  ) =>
  (acc: A): Either<L, A & Record<N, R>> =>
    f(acc).map(r => ({...acc, [name]: r} as A & Record<N, R>))

const userSettings: Either<string, UserSettings> = Right({})
  .chain(bind('userId', () => UserId.create('1234')))
  .chain(bind('email', () => Email.create('hello@world.com')))
  .chain(bind('active', () => Active.create(183)))
  .chain(bind('role', () => Role.create('admin')))
  .map(({userId, email, active, role}) => UserSettings(userId, email, active, role))

bind接受一个函数可以实现这样的功能:

代码语言:javascript
复制
Right({})
  .chain(bind('a', () => Right(1)))
  // The value of b depends on a
  .chain(bind('b', ({a}) => Right(a + 1)))
  // a is 1 and b is 2
  .map(({a, b}) => `a is ${a} and b is ${b}`)

这几乎是一个港口的fp-ts实现do表示法,所以所有的信用归于朱利奥坎蒂和贡献者的fp-ts。

如果您经常编写() =>,您可以使用另一个助手:

代码语言:javascript
复制
// This could definitely be named better
const bind_ = <N extends string, A extends object, L, R>(
  name: Exclude<N, keyof A>,
  either: Either<L, R>
): ((acc: A) => Either<L, A & Record<N, R>>) => bind(name, () => either)

const userSettings: Either<string, UserSettings> = Right({})
  .chain(bind_('userId', UserId.create('1234')))
  .chain(bind_('email', Email.create('hello@world.com')))
  .chain(bind_('active', Active.create(183)))
  .chain(bind_('role', Role.create('admin')))
  .map(({userId, email, active, role}) => UserSettings(userId, email, active, role))

操场链接

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67524514

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档