0
votes

I have a NameValuePair-interface and I want to write a function which "reduces" a list of Name-Value-pairs to a string. In this case the function would make a query string, e.g.

?name=foo&age=10

out of the given Name-Value-Pairs.

export interface NameValuePair {
  name: string,
  value: any
};

export const nameValuePairsToString = (
  pairs: NameValuePair[],
  innerSeperator: string="=", outerSeperator: string="&",
  startValue="?"
): string => (
  pairs.reduce((acc: string, pair: NameValuePair, idx: number): string => {
    const pairAsString = pair.name + innerSeperator + pair.value;
    const tail = idx === 0
      ? pairAsString
      : outerSeperator + pairAsString;
    return acc + tail;
}), startValue);

TypeScript throws this error at the definition of the anonymous function passed to the reducer:

Argument of type '(acc: string, pair: NameValuePair, idx: number) => string' is not assignable to parameter of type '(previousValue: NameValuePair, currentValue: NameValuePair, currentIndex: number, array: NameValuePair[]) => NameValuePair'. Types of parameters 'acc' and 'previousValue' are incompatible. Type 'NameValuePair' is not assignable to type 'string'.ts(2345)

Is it not possible to reduce an array of one type (NameValuePair) to another type (string). I thought that was the whole point of reducers? In JavaScript I always did used Array.prototype.reduce like that... Is it not possible in TypeScript or what did I do wrong?

1
First glance: double brackets (( at the reduce. First param should be the previous Value acc, not a callablek0pernikus
Please correct me if I’m wrong but I thought Array.reduce takes a function as the first argument (therefore the double brackets for an anonymous arrow function) and as the second argument the initValue.IceRevenge
I don’t think that is the problem either because if you write an arrow function without curly brackets (just paranthesis) you do not need to write the return keyword, instead the value is just returned per default. I think the problem lies in the anonymous function given per argument to the reduce because the error says that the types of the parameters of the functions do not fit (acc is string for me and it says it has to be a NameValuePair). I thought that reducers worked differently so that “previousValue” can be any kind of value...IceRevenge

1 Answers

2
votes

You had the brackets wrong.

Your opening bracket:

export const nameValuePairsToString = (...): string => (

is terminated here:

}), startValue);

It should have been:

}, startValue));

You can also omit it:

export const nameValuePairsToString = (
    pairs: NameValuePair[],
    innerSeperator: string = "=", outerSeperator: string = "&",
    startValue = "?"
): string => pairs.reduce((acc: string, pair: NameValuePair, idx: number): string => {
    const pairAsString = pair.name + innerSeperator + pair.value;
    const tail = idx === 0
        ? pairAsString
        : outerSeperator + pairAsString;
    return acc + tail;
}, startValue);

Or with the brackets:

export const nameValuePairsToString = (
    pairs: NameValuePair[],
    innerSeperator: string="=", outerSeperator: string="&",
    startValue="?"
): string =>
    (pairs.reduce((acc: string, pair: NameValuePair, idx: number): string => {
        const pairAsString = pair.name + innerSeperator + pair.value;
        const tail = idx === 0
            ? pairAsString
            : outerSeperator + pairAsString;
        return acc + tail;
    }, startValue));

You can see that it works via:

console.log(nameValuePairsToString([
    {name: 'foo', value: 'bar'}, 
    {name: 'age', value: 10}])
);

as it outputs:

?foo=bar&age=10