繁体   English   中英

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

[英]Type modeling with TypeScript and fp-ts and error while using Either

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

如果删除Either并返回总和类型, Error | MyValidType 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,
});

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

简短答案

TS> = 3.4

答案稍长

您可能已经注意到,TypeScript通常在推论方面并不出色。 在您的代码示例中,为函数Either<Error, MyValidType>的返回类型提供注释,以便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-in​​ference-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断言”更改此行为:

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拥有的createMyValidType

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM