从带有Sanctuary的某些RecordType的对象中挑选字段

时间:2017-10-05 13:52:41

标签: javascript functional-programming 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) => {};

要点:

  1. 我怎么写类型我的函数参数是正确的 (<some_type_for_validate_options><constructed_type_for_return>)?

  2. 如何使用避难功能编写函数体 组合物

  3. 感谢您的帮助:)

1 个答案:

答案 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 } -> UUIDUser或其他类型。)

因此,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中的记录时,我更喜欢编写稍微冗长但提供更强保证的代码。