【问题标题】:Filtering Lists of Maybes过滤可能的列表
【发布时间】:2020-03-17 08:51:28
【问题描述】:

如果我有一个Maybe<int>[],并且我只想获取不是None 的数组值,那么最好的方法是什么,并让 typescript 了解它得到了什么?

我假设输入的方式是说我最终会输入int[]。

我能做到:

const x: int[] = [1, 2, 3, null]
  .map(Maybe.fromNull)
  .filter(x => !x.isNone())
  .map(x => x.getOrElse(-1)) // this ought not to ever require the default value

但这感觉非常笨拙和冗长。我觉得我错过了一些更好的处理方式。

【问题讨论】:

  • 不确定有没有办法使用原生数组方法来做到这一点。数组类型(更抽象)Array<A | B> 但当您调用 .filter() 删除所有 As 时,类型不会改变,因为 .filter() 返回相同类型的数组。仅对于 TS,您可以使用类型断言,但在您的情况下,数组实际上包含具体对象。所有Maybes 不能只知道它们不是空的。至少可以说这是一个棘手的问题。
  • 顺便说一句,即使在 JS/TS 之外,您也会遇到类似的问题 - 当您尝试使用流/LINQ 操作时,我已经在 J​​ava 和 C# 中看到过,类型无法真正知道是什么到那时为止已经在链中完成了。您可以执行 .filter(x => x.id != null) 并且后面的操作无法知道 id 始终已设置 - 如果您尝试取消引用 .id 就像不为空一样,它们会警告您。
  • null 和Maybe 标记的联合有什么区别?对于后者,您不必检查 None 值,因为涉及的代码总是考虑这两种情况。这适用直到您折叠或消除标记的联合,就像您对getOrElse 所做的那样。给定的示例未按预期使用Maybe。
  • @bob 对于我正在使用的代码,当我与一些需要int[] 的代码进行交互时,就会出现问题,例如;在这种情况下,我很乐意从列表中删除任何不包含值的内容
  • @VLAZ 我完全同意; filter 改变类型真的没有意义。我将更多地解决这个问题,看看我能想出什么,作为记录,我遇到的实际问题是尝试在前端使用关系数据结构;对象通过 Ids 与其他对象相关,但并不能真正保证具有给定 id 的对象存在,这就是为什么我在这里开始使用也许

标签: typescript functional-programming monetjs


【解决方案1】:

您的问题的答案取决于 Maybe 的特定实现,所以我在下面包含了我正在使用的一个。基本上现在您需要明确地将函数注释为类型保护才能使其工作。有人谈到支持not T 类型需要!isNone() 才能工作,但到目前为止还没有发生。下面的代码确实有效:

const MaybeTag = Symbol("Maybe");

type Nothing<T> = { [MaybeTag]?: T; name: "Nothing" } ;
type Just<T> ={ [MaybeTag]?: T; name: "Just";  value: T } ;
type Maybe<T> = Just<T> | Nothing<T>

const Maybe = {
    Just<T>(value: T): Just<T> {
        return { name: "Just", value };
    },
    Nothing<T = never>(): Nothing<T> {
        return { name: "Nothing" };
    },
    isNothing<T>(maybe: Maybe<T>): maybe is Nothing<T> {
        return maybe.name === "Nothing";
    },
    isJust<T>(maybe: Maybe<T>): maybe is Just<T> {
        return maybe.name === "Just";
    },
    fromNull<T>(value: T | null | undefined): Maybe<T> {
        if (value == null) return Maybe.Nothing();
        return Maybe.Just(value);
    }
}

const x: number[] = [1, 2, 3, null]
  .map(Maybe.fromNull)
  .filter(Maybe.isJust)
  .map(x => x.value) // x is Just<number> as expected

const x: number[] = [1, 2, 3, null]
  .map(Maybe.fromNull)
  // Note the explicit type guard
  .filter(function<T>(x: Maybe<T>): x is Just<T> { 
    return !Maybe.isNothing(x);
  })
  .map(x => x.value) // x is Just<number> as expected

【讨论】:

    猜你喜欢
    • 2019-11-07
    • 1970-01-01
    • 2019-02-04
    • 1970-01-01
    • 1970-01-01
    • 2018-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多