当唯一的区别是 return 对象的键名时,最优雅的重构方法是什么?

What's the most elegant way to refactor this when the only difference is the key name of a return object?

当唯一的区别是 return 对象的键名时,最优雅的重构方法是什么?

function generateContactInput(rawData, contactId) {
  const data = rawData
    ? rawData.replace(/["]+/g, '').split(SEMICOLON)
    : undefined;
  const populatedData = data
    ? data.map((value) => ({ contactId, value }))
    : undefined;
  if (Array.isArray(populatedData) && populatedData.length > 0)
    populatedData[0].isPrimary = true;
  return populatedData;
}

function generateContactAddressInput(rawAddresses, contactId) {
  const data = rawAddresses
    ? rawAddresses.replace(/["]+/g, '').split(SEMICOLON)
    : undefined;
  const populatedData = data
    ? data.map((streetAddress) => ({ contactId, streetAddress }))
    : undefined;
  if (Array.isArray(populatedData) && populatedData.length > 0)
    populatedData[0].isPrimary = true;
  return populatedData;
}

唯一的区别是那一行:

? data.map((streetAddress) => ({ contactId, streetAddress }))

一种可能的方法是创建一个单独的辅助函数来接收要在映射中使用的名称:

function generateInput(rawData, contactId, fieldName) {
  const data = rawData
    ? rawData.replace(/["]+/g, '').split(SEMICOLON)
    : undefined;
  const populatedData = data
    ? data.map((value) => ({ contactId, [fieldName]: value }))
    : undefined;
  if (Array.isArray(populatedData) && populatedData.length > 0)
    populatedData[0].isPrimary = true;
  return populatedData;
}

...然后要么直接使用这个辅助函数,要么创建一系列具有预定义值的包装器:

function generateContactInput(rawData, contactId) {
  return generateInput(rawData, contactId, 'value');
}

function generateContactAddressInput(rawData, contactId) {
  return generateInput(rawData, contactId, 'streetAddress');
}

事实上,我也会考虑重写代码以删除三元组:

function generateInput(rawData, contactId, fieldName) {
  if (!rawData) return; // no need to drag this special case through the whole code

  const data = rawData.replace(/["]+/g, '').split(SEMICOLON);
  const populatedData = data.map((value) => ({ contactId, [fieldName]: value }));
  if (populatedData.length > 0) 
    populatedData[0].isPrimary = true;
  return populatedData;
}

如果您对函数式方法感兴趣,请告诉我

const compose = (...fns: any[]) => (data: any) => fns.reduceRight((acc, fn) => fn(acc), data);

const SEMICOLON = ';'

const rawInfo = (contactId, name) => (value) => ({ contactId, [name]: value })

const replace = (rawData) => rawData ? rawData.replace(/["]+/g, '').split(SEMICOLON) : undefined

const populate = (cb) => (data) => data ? data.map(cb) : undefined

const array = (data) => {
    if (Array.isArray(data) && data.length > 0) {
        const [head, ...tail] = data

        const newHead = {
            ...head,
            isPrimary: true
        }
        return [newHead, ...tail]
    }

    return data
}

const handler = (rawData, contactId, strategy: 'value' | 'streetAddress') =>
    compose(array, populate(rawInfo(contactId, strategy)), replace)(rawData)

Here 你可以找到我关于输入 compose 函数的文章