-1

I'm currently learning Typescript declarations, but I'm stuck on the concept of passing a varying number of parameters to a function.

In other words, how do I make a Typescript declaration for a JavaScript function like this:

// Formats a string with the supplied parameter(s)
// Examples Usage: 
//  formatString("User {0} logged in", 'John');
//  formatString("Max {0} words allowed", 128.8999);
//  formatString("Form {0} to {1}", [10, 100]);

const function FormatString(sTemplate, params) {
    if (typeof params != undefined && arguments.length == 2) {
        if (params.constructor != Array) {
            if (typeof params == 'string')
                params = [params];
            else
                params = [String(params)];
        }

        if (params.constructor == Array) {
            $.each(params, function (index, value) {
                if (typeof value == 'string')
                    sTemplate = sTemplate.replace(new RegExp("\\{" + index + "\\}", "g"), value);
                else
                    sTemplate = sTemplate.replace(new RegExp("\\{" + index + "\\}", "g"), String(value));
            });
        }
    }
    return sTemplate;
}
zeh
  • 10,130
  • 3
  • 38
  • 56
woosh
  • 1
  • Try to simplify example to a minimal problem – shusson Apr 01 '21 at 21:03
  • 3
    Please consider modifying the code in this question so as to constitute a [mcve] which, when dropped into a standalone IDE like [The TypeScript Playground](https://tsplay.dev/mL9XaW), clearly demonstrates the issue you are facing. This will allow those who want to help you to immediately get to work solving the problem without first needing to re-create it. And it will make it so that any answer you get is testable against a well-defined use case. What is `$`? What is `const function`? Can you describe what you actually intend to accept as `params`? Can it be anything at all? Et cetera. – jcalz Apr 01 '21 at 21:16

1 Answers1

0

Some tips:

  1. In JavaScript/TypeScript, don't use == and != when you want to mean strict equality or inequality; instead, do === and !==, otherwise the language perfoms a looser comparison (e.g. 4 == '4' is true, while 4 === '4' is false).
  2. To check if something is an Array, the more idiomatic solution is Array.isArray(obj).
  3. Try to avoid using arguments. It's considered bad practice and deprecated in practice, and some times not accessible at all. Using the rest parameter is usually better (safer, easier) to use.
  4. To convert number to string, prefer the .toString() method, which ensures that it's actually a proper value and errors when empty.
  5. No need to use $ or any fancy dependency for something like each(); array.forEach() should be well supported in browsers by now.

With all of that said, an opinionated rewrite of your code would be:

const formatString = (sTemplate: string, ...params: Array<string | number>) => {
    params.forEach((value, index) => {
        const newValue = typeof value === 'string' ? value : value.toString(10);
        sTemplate = sTemplate.replace(new RegExp("\\{" + index + "\\}", "g"), newValue);
    });
    return sTemplate;
};

formatString("User {0} logged in", 'John');
formatString("Max {0} words allowed", 128.8999);
formatString("Form {0} to {1}", 10, 100);

Notice additional params being allowed, rather than an array. While you can achieve what you have in your message (either a single param, or an array of params), I think it would be a bit non-idiomatic and likely to cause confusion.

In my above case, you can still pass an array as a parameter (if, say, it's generated somewhere else) by using an array spread like so:

const nums = [10, 100];
formatString("Form {0} to {1}", ...nums);

If you want to keep your original syntax, however, you can use it like this:

const formatString = (sTemplate: string, params?: Array<string | number> | string | number) => {
    if (params !== undefined) {
        const newParams = Array.isArray(params) ? params : [params];
        newParams.forEach((value, index) => {
            const newValue = typeof value === 'string' ? value : value.toString(10);
            sTemplate = sTemplate.replace(new RegExp("\\{" + index + "\\}", "g"), newValue);
        });
    }
    return sTemplate;
};

formatString("User {0} logged in", 'John');
formatString("Max {0} words allowed", 128.8999);
formatString("Form {0} to {1}", [10, 100]);
formatString("No params");

But one additional caveat is that you can't use undefined as an actual parameter if if it's a single parameter; it'll assume it's not there and not perform the replacement in the template.

Good luck on your learning journey! JavaScript is a language that has some gotchas like the ==/!= case mentioned above, but TypeScript certainly makes it easier to get to valid, safe code, so I would recommend staying in that path!

zeh
  • 10,130
  • 3
  • 38
  • 56