Выбор полей из объекта с определенным RecordType с 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,
});
И я хочу создать функцию, которая выбирает параметры из таких записей, как 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?
Спасибо за любую помощь:)
1 ответ
В 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 => ???
);
Какова реализация, которая должна появиться вместо ???
, Ответ может быть удивительным: мы просто возвращаемся 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})
);
Это более многословно, чем R.pick
эквивалентно, но это цена, которую мы должны заплатить, чтобы иметь дело с записями более дисциплинированным образом, чем того требует JavaScript.
Я могу представить, что однажды мы добавим такую функцию в Sanctuary:
S.pick :: Set String -> StrMap a -> StrMap a
Я не могу представить, однако, подобную функцию, работающую с произвольными записями, так как мы были бы вынуждены использовать свободный тип, такой как Set String -> Object -> Object
, При работе с записями в Sanctuary я предпочитаю писать код, который немного более многословен, но дает более сильные гарантии.