使用TypeScript和fp-ts进行类型建模以及使用Either时出错

时间:2019-02-05 18:53:23

标签: typescript functional-programming fp-ts

我正在尝试使用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) => Either<Error, { id: string; isValid: boolean; }>' is not assignable to type 'Either<Error, CreateMyValidType>'.

如果我删除了Either而只返回了总和类型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,
});

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

1 个答案:

答案 0 :(得分:2)

简短答案

在TS> = 3.4

下可以正常使用

答案略长

您可能已经注意到,TypeScript通常在推理方面并不出色。 在您的代码示例中,为函数Either<Error, MyValidType>的返回类型提供注释,以便TS可以尝试将所有分支统一为期望的返回类型:如果没有此显式注释,结果将更糟。 / p>

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

boolean

在TS> = 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'. 的情况下,3.4会一直处于“不确定状态”,直到TS真正知道预期的{带注释的)返回类型R并正确看到可分配给声明的返回类型的文字对象。

您可以在https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#higher-order-type-inference-from-generic-functions

上了解有关此改进的更多信息。

注释1

该问题与createMyValidType并没有真正的关系,因为对于任何泛型函数,在3.4之前都发生了类似的问题:

fp-ts

注释2

查看此示例的另一种方法是,默认情况下,TS不会推断出最精确的可能的文字类型,除了某些特殊情况:

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"'.

考虑到JS的可变性,这是“安全”的默认设置。可以使用“ const foo = 'foo' // Type: "foo" const fooObj = { foo: 'foo' } // Type: { foo: string } 断言”来更改此行为:

const

这是const fooObj = { foo: 'foo' } as const // Type: { readonly foo: "foo" } 中的另一项附加内容(请参见https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#const-assertions),由于您在3.4中具有返回类型注释,因此在示例中并非必须如此。