Some tips:
- 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'istrue, while4 === '4'isfalse).
- To check if something is an Array, the more idiomatic solution isArray.isArray(obj).
- 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.
- To convert numbertostring, prefer the.toString()method, which ensures that it's actually a proper value and errors when empty.
- No need to use $or any fancy dependency for something likeeach();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!