使用 Sanctuary 从具有特定 RecordType 的对象中选取字段
Picking fields from object with certain RecordType with Sanctuary
我有一个对象,其选项对应于以下记录类型:
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>
)?
如何使用避难所函数编写函数体
作曲?
感谢您的帮助:)
在 Sanctuary 中,通常不需要从记录中选择某些字段。考虑这个模块:
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 => ???
);
代替 ???
应该出现的实现是什么。答案可能令人惊讶:我们只是 return user
。这是因为 User
类型的每个成员也是 MinimalUser
类型的成员。允许记录包含附加字段。这使得可以定义类型为 id :: { id :: UUID } -> UUID
的函数,这些函数不限于特定类型(User
、Invoice
或其他类型)。
所以,toMinimalUser
可能是不必要的。由于 User
类型的每个成员也是 MinimalUser
类型的成员,我们可以将 User
/MinimalUser
传递给需要 MinimalUser
的函数.
尽管类型系统不要求我们“剥离”字段,但出于隐私原因,我们可能希望这样做。考虑 toJson :: User -> String
。如果我们从 User
值构建 API 响应,出于隐私原因,我们可能会排除 email
字段。在这种情况下,我会建议这个实现:
// toJson :: User -> String
const toJson = def(
'toJson',
{},
[User, $.String],
({id, username}) => JSON.stringify({id, username})
);
这比 R.pick
等价物更冗长,但这是我们必须付出的代价,才能以比 JavaScript 所要求的更规范的方式处理记录。
我可以想象有一天我们会在 Sanctuary 中添加这样的功能:
S.pick :: Set String -> StrMap a -> StrMap a
不过,我无法想象在任意记录上运行类似的函数,因为我们将被迫使用松散类型,例如 Set String -> Object -> Object
。在处理 Sanctuary 中的记录时,我更喜欢编写稍微冗长但提供更强保证的代码。
我有一个对象,其选项对应于以下记录类型:
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>
)?如何使用避难所函数编写函数体 作曲?
感谢您的帮助:)
在 Sanctuary 中,通常不需要从记录中选择某些字段。考虑这个模块:
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 => ???
);
代替 ???
应该出现的实现是什么。答案可能令人惊讶:我们只是 return user
。这是因为 User
类型的每个成员也是 MinimalUser
类型的成员。允许记录包含附加字段。这使得可以定义类型为 id :: { id :: UUID } -> UUID
的函数,这些函数不限于特定类型(User
、Invoice
或其他类型)。
所以,toMinimalUser
可能是不必要的。由于 User
类型的每个成员也是 MinimalUser
类型的成员,我们可以将 User
/MinimalUser
传递给需要 MinimalUser
的函数.
尽管类型系统不要求我们“剥离”字段,但出于隐私原因,我们可能希望这样做。考虑 toJson :: User -> String
。如果我们从 User
值构建 API 响应,出于隐私原因,我们可能会排除 email
字段。在这种情况下,我会建议这个实现:
// toJson :: User -> String
const toJson = def(
'toJson',
{},
[User, $.String],
({id, username}) => JSON.stringify({id, username})
);
这比 R.pick
等价物更冗长,但这是我们必须付出的代价,才能以比 JavaScript 所要求的更规范的方式处理记录。
我可以想象有一天我们会在 Sanctuary 中添加这样的功能:
S.pick :: Set String -> StrMap a -> StrMap a
不过,我无法想象在任意记录上运行类似的函数,因为我们将被迫使用松散类型,例如 Set String -> Object -> Object
。在处理 Sanctuary 中的记录时,我更喜欢编写稍微冗长但提供更强保证的代码。