【问题标题】:TypeScript functional programming patterns for comfortable object construction?用于舒适对象构造的 TypeScript 函数式编程模式?
【发布时间】:2022-10-05 17:09:22
【问题描述】:

我很难找到函数式编程对象构造模式的示例(视频或博客)。

我最近遇到了以下截断的构建器模式,我喜欢它为构建带有嵌套的对象提供的体验。当它是一个更扁平的对象时,我通常会使用一个简单的对象工厂和一个 opts 参数来传播默认值,但是传入一个嵌套的对象数组开始感觉混乱。

是否有 FP 模式可以帮助通过嵌套像下面这样舒适地组合对象,同时允许调用某些方法 n 次,例如 addStringOption

const data = new SlashCommandBuilder()
    .setName(\'echo\')
    .setDescription(\'Replies with your input!\')
    .addStringOption(option =>
        option.setName(\'input\')
            .setDescription(\'The input to echo back\')
            .setRequired(true)
    )
    .addStringOption(option =>
        option.setName(\'category\')
            .setDescription(\'The gif category\')
            .setRequired(true)
            .addChoices(
                { name: \'Funny\', value: \'gif_funny\' },
                { name: \'Meme\', value: \'gif_meme\' },
                { name: \'Movie\', value: \'gif_movie\' },
  ));

data 最终看起来像:

{
  name: \"echo\",
  description: \"Replies with your input!\",
  options: [
    {
      name: \"input\",
      description: \"The input to echo back\",
      type: 7, // string option id
      required: true,
      choices: null,
    },
    {
      name: \"category\",
      description: \"The gif category\",
      required: true,
      type: 7,
      choices: [
        { name: \"Funny\", value: \"gif_funny\" },
        { name: \"Meme\", value: \"gif_meme\" },
        { name: \"Movie\", value: \"gif_movie\" },
      ],
    },
  ],
};

下面是我正在玩的东西。我仍在努力学习如何在 TS 中输入它们,所以我正在分享 JS。

在下面的 sn-p 中允许方法链接可能会过多地扭曲 FP,使其像 OOP,但我还没有找到一种可以很好地使构造流程顺畅的替代方法。

另一种选择可能是独立的构建器,每个构建器返回一个返回更新状态的回调,然后将这些构建器连接在一起,但是由于某些构建器是可调用的n,因此很难提前制作和提供管道并且没有点符号提供智能感知似乎更难知道可用的功能是用什么来构建的。

const buildCommand = () => {
  // data separate from methods.
  let command = {
    permissions: [\'admin\'],
    foo: \'bar\',
    options: [],
  };

  const builders = {
    setGeneralCommandInfo: ({ name, description }) => {
      command = { ...command, name, description };
      // trying to avoid `this`
      return builders;
    },

    setCommandPermissions: (...permissions) => {
      command = { ...command, permissions };
      return builders;
    },

    addStringOption: (callback) => {
      const stringOption = callback(buildStringOption());
      command = { ...command, options: [...command.options, stringOption] };
      return builders;
    },
    // can validate here
    build: () => command,
  };

  return builders;
};

const buildStringOption = () => {
  let stringOption = {
    choices: null,
    type: 7,
  };

  const builders = {
    setName: (name) => {
      stringOption = { ...stringOption, name };
      return builders;
    },

    setDescription: (description) => {
      stringOption = { ...stringOption, description };
      return builders;
    },

    addChoices: (choices) => {
      stringOption = { ...stringOption, choices };
      return builders;
    },

    build: () => stringOption,
  };

  return builders;
};

const command1 = buildCommand()
  .setGeneralCommandInfo({ name: \'n1\', description: \'d1\' })
  .setCommandPermissions(\'auditor\', \'moderator\')
  .addStringOption((option) =>
    option.setName(\'foo\').setDescription(\'bar\').build()
  )
  .addStringOption((option) =>
    option
      .setName(\'baz\')
      .setDescription(\'bax\')
      .addChoices([
        { name: \'Funny\', value: \'gif_funny\' },
        { name: \'Meme\', value: \'gif_meme\' },
      ])
      .build()
  )
  .build();

console.log(command1);
  • 首先,我不会使用如此深度嵌套的对象。相反,我看到三个或更多类的外部类具有要使用其他两个类的对象设置的字段。这将其分解为块,特别是为嵌套的块提供有意义的名称。如果您愿意,构建块可能只需要一个构造函数或一个非常简单的构建器。
  • @Harald 这就是示例构建器的工作方式,但在 FP 中,我认为通常会避免混合方法和数据的类,所以我试图不使用类。

标签: javascript typescript oop constructor functional-programming


【解决方案1】:

为什么不简单地创建和使用数据构造函数?

const SlashCommand = (name, description, options) =>
  ({ name, description, options });

const StringOption = (name, description, required, type = 7, choices = null) =>
  ({ name, description, required, type, choices });

const Choice = (name, value) => ({ name, value });

const data = SlashCommand('echo', 'Replies with your input!', [
  StringOption('input', 'The input to echo back', true),
  StringOption('category', 'The gif category', true, undefined, [
    Choice('Funny', 'gif_funny'),
    Choice('Meme', 'gif_meme'),
    Choice('Movie', 'gif_movie')
  ])
]);

console.log(data);

TypeScript Playground Example

您无法获得比这更多的功能。 Intellisense 还将帮助您处理构造函数参数。

【讨论】:

    猜你喜欢
    • 2017-09-22
    • 2012-05-24
    • 2015-10-06
    • 1970-01-01
    • 2018-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多