TypeScript函数式编程模式用于舒适的对象构造



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

我最近遇到了下面的构建器模式,我喜欢它为构建带有嵌套的对象提供的经验。当它是一个更平坦的对象时,我通常只使用一个带有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。

在下面的代码段中允许方法链接可能会过度扭曲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);

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

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游乐场示例

你再也没有比这更实用的了。Intellisense还将帮助您使用构造函数参数。

最新更新