Flow 中的可组合合同和积极合同
Composable and positive contracts in Flow
我在使用 Flow 时遇到问题,其中给定的实现 type
通过要求我仅使用在 type
上声明的属性而不是来限制我的对象 API要求我声明 type
的所有属性。
我是 Flow 的新手,所以我可能犯了一些基本错误之类的。无论如何,我声明了这个 type
:
type Unit = {
of(value: any): Monad,
};
我想在这里做的是说:所有根据Unit
实现的对象必须有一个#of
方法接收给定的value
和returns 一个 Monad
类型的值。
当我在我的工厂实施它时没有出现问题:
const Maybe: Unit = {
isMaybe: (obj): boolean => { ... },
of: (value): Monad => { ... },
};
但是当我尝试调用 #isMaybe
时,我得到了这个错误(在 linter 上):
flow(0|2), isMaybe (Cannot call: `Maybe.isMaybe` because property `isMaybe` is missing in `Unit` [1].)
现在我尝试在 Unit
上声明 #isMaybe
并且错误按预期消失了。问题是,Unit
应该是一种自由接口,检查它的实现是否具有 Unit
属性而不是 only Unit
属性。
我无法重构 - 至少我不知道 - Unit
从 type
到 interface
因为我正在通过 is-a
关系组合它们:
type Monad = Applicative & Chain; // Monad is-a Applicative and a Chain
有什么方法可以使合同既积极又可与 Flow 组合?
我不太了解你所说的 'Is there any way to make a contract both positive and composable with Flow?' 是什么意思(我假设这是来自另一种语言?),而且我没有按照你描述的方式使用流程;这是将函数定义定义为类型的一部分,但我希望我在这里的方法对您有所帮助。
我在这里要做的第一件事是为 MaybeUnit
创建第二种类型
export type MaybeUnit = Unit &{
isMaybe: (obj): boolean
};
但是,再一次,我不熟悉该函数是类型的一部分。任何时候我想要一个函数,我都会定义一个 class (可能有一个接口)而不是一个类型。这可能会将您的实现更改为如下所示:
interface IUnit {
of(value: any): Monad;
}
class Unit implements IUnit {
of(value): Monad {
return new Monad();
}
}
interface IMaybeUnit extends IUnit {
isMaybe({}): boolean;
}
class MaybeUnit extends Unit implements IMaybeUnit {
isMaybe({}): boolean {
return true;
}
}
希望这种方法能解决您的问题。
更新:添加一个我有时对经理所做的事情的例子 classes。这是一种非常冗长的方法,仅适用于某些情况。当使用流运行时以便在执行时而不是仅在构建时测试类型时,它也更有用。
class UnitManager {
static UnitTypes:Map<string, IUnit>;
static RegisterUnitType( key:string, klass:Class ) {
UnitManager.UnitTypes.set( key, klass );
}
static CreateUnit( unit:IUnit ):Unit {
// test data to determine type
let type:string = UnitManager.GetUnitType( unit );
let klass:Class = UnitManager.UnitTypes.get( type );
return new klass( unit );
}
static GetUnitType( unit:IUnit ):IUnit {
// Magic. Your logic to determine the type based on the data provided. if you use flow-runtime, you can use instanceOf, otherwise I think you need to test if the keys exist in the data, or something.
}
}
我最初没有包含它,因为它不是很干净,而且通常是一种反模式。它在某些情况下很有用,我发现自己主要使用它来避免循环依赖。
有时我会拥有它,以便每个 class' 构造函数根据 class.
中的静态 'name' 常量将自己注册到管理器
我对positive和composable也不太熟悉,但我认为interface
s可以帮助解决问题。您可以轻松扩展 interface
并将变量声明为一个。查看下面的示例,了解如何使用和扩展接口。请注意,在这种特殊情况下无需通过 类。
type Monad = any;
interface Unit {
of(value: any): Monad;
}
const unit: Unit = {
of(value: any): Monad {
return value;
}
}
const notUnit: Unit = {};
const alsoNotUnit: Unit = {
isMaybe(value: any): boolean {
return false;
}
}
interface Maybe extends Unit {
isMaybe(value: any): boolean;
}
const maybe: Maybe = {
isMaybe(value: any): boolean {
return true;
},
of(value: any): Monad {
return value;
}
}
const notMaybe: Maybe = {
isMaybe(value: any): boolean {
return true;
}
};
const alsoNotMaybe: Maybe = {
of(value: any): Monad {
return value;
}
}
作为警告,因为我看到您使用了 &
交集类型运算符——交集类型目前在 Flow 中已损坏且不一致。我建议暂时不要使用它们。他们的大部分行为都可以通过其他更正确的方式来完成,例如展开运算符或 extends
.
我在使用 Flow 时遇到问题,其中给定的实现 type
通过要求我仅使用在 type
上声明的属性而不是来限制我的对象 API要求我声明 type
的所有属性。
我是 Flow 的新手,所以我可能犯了一些基本错误之类的。无论如何,我声明了这个 type
:
type Unit = {
of(value: any): Monad,
};
我想在这里做的是说:所有根据Unit
实现的对象必须有一个#of
方法接收给定的value
和returns 一个 Monad
类型的值。
当我在我的工厂实施它时没有出现问题:
const Maybe: Unit = {
isMaybe: (obj): boolean => { ... },
of: (value): Monad => { ... },
};
但是当我尝试调用 #isMaybe
时,我得到了这个错误(在 linter 上):
flow(0|2), isMaybe (Cannot call: `Maybe.isMaybe` because property `isMaybe` is missing in `Unit` [1].)
现在我尝试在 Unit
上声明 #isMaybe
并且错误按预期消失了。问题是,Unit
应该是一种自由接口,检查它的实现是否具有 Unit
属性而不是 only Unit
属性。
我无法重构 - 至少我不知道 - Unit
从 type
到 interface
因为我正在通过 is-a
关系组合它们:
type Monad = Applicative & Chain; // Monad is-a Applicative and a Chain
有什么方法可以使合同既积极又可与 Flow 组合?
我不太了解你所说的 'Is there any way to make a contract both positive and composable with Flow?' 是什么意思(我假设这是来自另一种语言?),而且我没有按照你描述的方式使用流程;这是将函数定义定义为类型的一部分,但我希望我在这里的方法对您有所帮助。
我在这里要做的第一件事是为 MaybeUnit
export type MaybeUnit = Unit &{
isMaybe: (obj): boolean
};
但是,再一次,我不熟悉该函数是类型的一部分。任何时候我想要一个函数,我都会定义一个 class (可能有一个接口)而不是一个类型。这可能会将您的实现更改为如下所示:
interface IUnit {
of(value: any): Monad;
}
class Unit implements IUnit {
of(value): Monad {
return new Monad();
}
}
interface IMaybeUnit extends IUnit {
isMaybe({}): boolean;
}
class MaybeUnit extends Unit implements IMaybeUnit {
isMaybe({}): boolean {
return true;
}
}
希望这种方法能解决您的问题。
更新:添加一个我有时对经理所做的事情的例子 classes。这是一种非常冗长的方法,仅适用于某些情况。当使用流运行时以便在执行时而不是仅在构建时测试类型时,它也更有用。
class UnitManager {
static UnitTypes:Map<string, IUnit>;
static RegisterUnitType( key:string, klass:Class ) {
UnitManager.UnitTypes.set( key, klass );
}
static CreateUnit( unit:IUnit ):Unit {
// test data to determine type
let type:string = UnitManager.GetUnitType( unit );
let klass:Class = UnitManager.UnitTypes.get( type );
return new klass( unit );
}
static GetUnitType( unit:IUnit ):IUnit {
// Magic. Your logic to determine the type based on the data provided. if you use flow-runtime, you can use instanceOf, otherwise I think you need to test if the keys exist in the data, or something.
}
}
我最初没有包含它,因为它不是很干净,而且通常是一种反模式。它在某些情况下很有用,我发现自己主要使用它来避免循环依赖。
有时我会拥有它,以便每个 class' 构造函数根据 class.
中的静态 'name' 常量将自己注册到管理器我对positive和composable也不太熟悉,但我认为interface
s可以帮助解决问题。您可以轻松扩展 interface
并将变量声明为一个。查看下面的示例,了解如何使用和扩展接口。请注意,在这种特殊情况下无需通过 类。
type Monad = any;
interface Unit {
of(value: any): Monad;
}
const unit: Unit = {
of(value: any): Monad {
return value;
}
}
const notUnit: Unit = {};
const alsoNotUnit: Unit = {
isMaybe(value: any): boolean {
return false;
}
}
interface Maybe extends Unit {
isMaybe(value: any): boolean;
}
const maybe: Maybe = {
isMaybe(value: any): boolean {
return true;
},
of(value: any): Monad {
return value;
}
}
const notMaybe: Maybe = {
isMaybe(value: any): boolean {
return true;
}
};
const alsoNotMaybe: Maybe = {
of(value: any): Monad {
return value;
}
}
作为警告,因为我看到您使用了 &
交集类型运算符——交集类型目前在 Flow 中已损坏且不一致。我建议暂时不要使用它们。他们的大部分行为都可以通过其他更正确的方式来完成,例如展开运算符或 extends
.