crazyones110
crazyones110

Reputation: 397

Refactor javascript code more elegantly, not using nested ternary expression or let

I have this simplified code, quite simple:

export const OwnRedirect = () => {
  const { pipelineType, ticketId, productId } = useParams<{
    pipelineType?: string;
    ticketId?: string;
    productId?: string;
  }>();
  let path = '';
  if (pipelineType) {
    path = `/pipeline/${pipelineType}`;
  } else if (ticketId) {
    path = `/ticket/${ticketId}`;
  } else if (productId) {
    path = `/product/${productId}`;
  } else {
    path = '/pipeline/local';
  }
  return <Redirect to={path}/>;
};

But I found it not readable enough. Anybody has an idea how to refactor this code not using if or switch or let or nested ternary operator?

Upvotes: 0

Views: 296

Answers (3)

Mat&#237;as Fidemraizer
Mat&#237;as Fidemraizer

Reputation: 64943

You may use a tagged sum. For example:

// Generic functions
// B is the function compose combinator
const B = g => f => x => g (f (x))

const taggedSum = xs => Object.fromEntries (
  xs.map(tag => [tag, value => ({ tag, value })])
)

const cata = matches => ({ tag, value }) => matches[tag] (value)
/////////////////////////

const Kind = taggedSum (['pipeline', 'ticket', 'product', 'local' ])

const path = cata ({
    pipeline: x => `/pipeline/${x}`,
    ticket: x => `/ticket/${x}`,
    product: x => `/product/${x}`,
    local: () => `/pipeline/local`
})

const output1 = B (path) (Kind.pipeline) (1)
const output2 = B (path) (Kind.ticket) (14)
const output3 = B (path) (Kind.product) (3421)
const output4 = B (path) (Kind.local) (0)


console.log ('pipeline:', output1)
console.log ('ticket:', output2)
console.log ('product:', output3)
console.log ('local:', output4)

Upvotes: 0

Hitmands
Hitmands

Reputation: 14189

sometimes just separating it into a function helps with readability.

const toUrl = ({ pipelineType = '', ticketId = '', productId = '' }) => {
  if (pipelineType) {
    return `/pipeline/${pipelineType}`;
  } 
  
  if (ticketId) {
    return `/ticket/${ticketId}`;
  } 
  
  if (productId) {
    return `/product/${productId}`;
  }
  
  return '/pipeline/local';
}


export const OwnRedirect = () => {
  const params = useParams<{
    pipelineType?: string;
    ticketId?: string;
    productId?: string;
  }>();
  
  return <Redirect to={toUrl(params)}/>;
};

Upvotes: 0

blex
blex

Reputation: 25659

To make it easier to read, you can take advantage of short-circuit evaluation with && and ||. To make things cleaner and easier to test, I also like creating really small functions that only do one thing, but do it well. It avoids mixing logic (which path to choose) and functionality (building those paths):

export const OwnRedirect = () => {
  const { pipelineType, ticketId, productId } = useParams<{
    pipelineType?: string;
    ticketId?: string;
    productId?: string;
  }>();
  
  const path = (
    (pipelineType && buildPipelinePath(pipelineType)) ||
    (ticketId     && buildTicketPath(ticketId)      ) ||
    (productId    && buildProductPath(productId)    ) ||
    `/pipeline/local`
  );

  return <Redirect to={path} />;
};

function buildPipelinePath(pipelineType) {
  return `/pipeline/${Number(pipelineType) === 1 ? 'local' : 'global'}`;
}

function buildTicketPath(ticketId) {
  return `/ticket/${ticketId}`;
}

function buildProductPath(productId) {
  return `/product/${productId}`;
}

Upvotes: 1

Related Questions