我有一个对象,其选项对应于以下记录类型:
const AwsRegionsEnum = $.EnumType(
'AWS/Regions',
'http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html',
[
'us-east-1',
'us-east-2',
'us-west-1',
'us-west-2',
'ca-central-1',
'eu-west-1',
'eu-central-1',
'eu-west-2',
'ap-northeast-1',
'ap-northeast-2',
'ap-southeast-1',
'ap-southeast-2',
'ap-south-1',
'sa-east-1',
]
);
const Credentials = $.RecordType({
accessKeyId: $.String,
secretAccessKey: $.String,
region: AwsRegionsEnum,
});
const PullOpts = $.RecordType({
waitTimeSeconds: S.MaybeType($.Number),
maxNumberOfMessages: S.MaybeType($.Number),
credentials: Credentials,
});
我想创建一个函数,从ramda库中的R.pick
等记录中选择选项。但我想输入列表字段进行拣选。该列表只能包含对PullOpts
类型记录有效的字段。
该功能的预期行为:
// pickOpts :: List(<some_type_for_validate_options>) -> PullOpts -> <constructed_type_for_return>
const pickOpts = (pickingOpts, allOpts) => {};
要点:
我怎么写类型我的函数参数是正确的
(<some_type_for_validate_options>
和
<constructed_type_for_return>
)?
如何使用避难功能编写函数体 组合物
感谢您的帮助:)
答案 0 :(得分:4)
在Sanctuary中,通常没有必要从记录中挑选某些字段。考虑一下这个模块:
uploadAll(files): void {
let fileUploadObservables = [];
files.forEach(file => {
fileUploadObservables
.push(this.fileUploadService.upload(file));
});
Observable.forkJoin(...fileUploadObservables)
.subscribe((res) => {
//Do something else when all files finish uploading
});
}
应该代替const $ = require('sanctuary-def');
const types = require('./types');
const def = $.create({checkTypes: true, env: $.env});
// User :: Type
const User = $.RecordType({
id: types.UUID,
username: $.NonEmpty($.String),
email: types.Email,
});
// MinimalUser :: Type
const MinimalUser = $.RecordType({
id: types.UUID,
username: $.NonEmpty($.String),
});
// toMinimalUser :: User -> MinimalUser
const toMinimalUser = def(
'toMinimalUser',
{},
[User, MinimalUser],
user => ???
);
显示什么实现。答案可能令人惊讶:我们只返回???
。这是因为user
类型的每个成员也是User
类型的成员。允许记录包含其他字段。这样就可以定义具有MinimalUser
类型的函数,这些类型不限于特定类型(id :: { id :: UUID } -> UUID
,User
或其他类型。)
因此,Invoice
可能是不必要的。由于toMinimalUser
类型的每个成员也是User
类型的成员,因此我们可以将MinimalUser
/ User
传递给期望MinimalUser
的函数
虽然类型系统不会要求我们“删除”字段,但出于隐私原因,我们可能希望这样做。考虑MinimalUser
。如果我们从toJson :: User -> String
值构建API响应,出于隐私原因,我们可能会排除User
字段。在这种情况下,我会建议这个实现:
email
这比// toJson :: User -> String
const toJson = def(
'toJson',
{},
[User, $.String],
({id, username}) => JSON.stringify({id, username})
);
等价物更详细,但这是我们必须付出的代价才能以比JavaScript要求更严格的方式处理记录。
我可以想象我们有一天会向Sanctuary添加这样的功能:
R.pick
但是,我无法想象,在任意记录上运行的类似函数因为我们被迫使用松散类型,例如S.pick :: Set String -> StrMap a -> StrMap a
。在处理Sanctuary中的记录时,我更喜欢编写稍微冗长但提供更强保证的代码。