[英]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将是“懒惰”,并试图解决由声明的所有泛型类型参数left
和right
的功能(包括有L
和R
类型参数)的地方,没有“等待”到在做出选择之前先获得更好的知识。 因此,它将在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.4
, R
将保持“不确定”状态,直到过程稍后,当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
断言”更改此行为:
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.