【问题标题】:Type modeling with TypeScript and fp-ts and error while using Either使用 TypeScript 和 fp-ts 进行类型建模以及使用 Either 时出现错误
【发布时间】:2019-02-05 18:53:23
【问题描述】:

我正在尝试使用 TypeScript 和 fp-ts 来让我的脚湿透建模 具有类型的域逻辑,我遇到了这个问题:

import { left, right, Either } from "fp-ts/lib/Either";

type MyType = {
  id: string,
  isValid: boolean,
}

type MyValidType = {
  id: string,
  isValid: true,
}

type CreateMyValidType = (t: MyType) => Either<Error, MyValidType>

// Compile error!
const createMyValidType: CreateMyValidType = t => {
  switch (t.isValid) {
    case true:
      return right({
        id: "test",
        isValid: true
      })
    default:
      return left(new Error())
  }
}

编译器对我大喊大叫是因为: Type '(t: MyType) =&gt; Either&lt;Error, { id: string; isValid: boolean; }&gt;' is not assignable to type 'Either&lt;Error, CreateMyValidType&gt;'.

如果我删除 Either 并且只返回 sum 类型 Error | MyValidType 就可以了。

type CreateMyValidType = (t: MyType) => Error | MyValidType

// This compiles
const createMyValidType: CreateMyValidType = t => {
  switch (t.isValid) {
    case true:
      return {
        id: "test",
        isValid: true
      }
    default:
      return new Error()
  }
}

当它在Either 中时,它似乎无法识别正确的类型!

我找到了通过在调用 right 时指定类型来避免该问题的方法,但我不完全理解其中的含义,所以我不知道这是否是一个坏主意:

return right<Error, MyType2>({
  id: "test",
  isValid: true,
});

处理此问题并使其编译的正确方法是什么? 谢谢!

【问题讨论】:

    标签: typescript functional-programming fp-ts


    【解决方案1】:

    简答

    它与 TS 一起按预期工作 >= 3.4

    答案稍长

    您可能已经注意到,TypeScript 通常并不擅长推理。 在您的代码示例中,您为函数Either&lt;Error, MyValidType&gt; 的返回类型提供了注解,以便TS 可以尝试将所有分支统一为预期的返回类型:如果没有此显式注解,结果会更糟。

    即使使用手动类型注释,3.4 之前的 TS 也会“惰性”并尝试解析由 leftright 函数声明的所有泛型类型参数(两者都有 LR 作为类型参数)就位,而无需“等待”在做出选择之前获得更好的知识。 因此,对于default 情况,它会将Error 推断为L,对于true 情况,将{ id: string, isValid: boolean } 推断为R。问题是MyValidType 要求isValid 是文字true(比boolean 更具体),所以它最终失败了

    Type '{ id: string; isValid: boolean; }' is not assignable to type 'MyValidType'.
      Types of property 'isValid' are incompatible.
        Type 'boolean' is not assignable to type 'true'.
    

    对于 TS >= 3.4R 处于“未决定”状态,直到该过程的后期,当 TS 实际上知道预期的(带注释的)返回类型 createMyValidType,并正确地将文字对象视为可分配给声明的返回类型。

    您可以在https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#higher-order-type-inference-from-generic-functions 的官方更新日志中阅读有关此改进的更多信息

    注 1

    这个问题与fp-ts 没有真正的关系,因为任何通用函数在 3.4 之前都会出现类似的问题:

    declare function identity<T>(t: T): T;
    
    function f(): { foo: 'foo' } {
      return identity({ foo: 'foo' });
    }
    // Type '{ foo: string; }' is not assignable to type '{ foo: "foo"; }'.
    //   Types of property 'foo' are incompatible.
    //     Type 'string' is not assignable to type '"foo"'.
    

    注2

    另一种看待这个例子的方式是,TS 默认情况下不会推断出最精确的可能文字类型,除了一些特定情况:

    const foo = 'foo' // Type: "foo"
    
    const fooObj = { foo: 'foo' } // Type: { foo: string }
    

    考虑到 JS 的可变性,这是一个“安全”的默认值。可以使用“const assertions”更改此行为:

    const fooObj = { foo: 'foo' } as const // Type: { readonly foo: "foo" }
    

    这是3.4 中的另一个添加(请参阅https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#const-assertions),由于您在createMyValidType 中具有返回类型注释,因此在您的示例中并不严格需要它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-03
      • 1970-01-01
      • 2018-12-20
      • 2020-09-15
      • 1970-01-01
      • 2020-11-22
      • 2021-07-17
      • 1970-01-01
      相关资源
      最近更新 更多