Tslint: Rule suggestion: strict-string-expressions (no implicit function to string)

Created on 8 Feb 2019  ·  8Comments  ·  Source: palantir/tslint

Rule Suggestion

There is some common pattern

const barFunc = () => 'World';
const fooStr = `Hello, ${barFunc()}`; // Hello, World

But it's easy to miss brackets around function and this would be not an error

const barFunc = () => 'World';
const fooStr = `Hello, ${barFunc}`; // "Hello, () => 'World'"

What does your suggested rule do?

If it's on, require explicit toString or String call around function

Like this

// yeah, we really want function source code here
const barFunc = () => 'World';
const fooStr = `Hello, ${String(barFunc)}`; // "Hello, () => 'World'"

Additional context

What about spreading this rule for other data types?

I think this is frustrating sometimes:

const name = { foo: 'Foo' };
alert('Hello, ' + name); // Hello, [object Object] (╯°□°)╯︵ ┻━┻ 

What do you think?

Requires Type Checker Accepting PRs Rule Suggestion

Most helpful comment

I was just looking for a rule for this. https://github.com/Microsoft/vscode/issues/68966

Meaning: primitives and objects/instances with their own toString are fine, but regular methods and functions aren't? What about arrays, unknowns, anys, and type unions or intersections?

Yes, I would want something specifically for functions and methods, (or type unions that could represent functions). I think that's the mistake that I'm most likely to make. It could also be useful for arrays, objects that don't have a non-default toString method, unknown etc.

All 8 comments

@ColCh this is a really interesting idea, thanks! I've definitely felt the exact pain you've described, and would like to see a rule helping.

On the other hand, the following should be allowed, right?

class CanBeStringified {
    toString() {
        return "This works fine...";
    }
}

const stringified = new CanBeStringified();

alert(`Result: ${stringified}`);

So is it that this rule should ban objects that whose toString is "reasonable"? Meaning: primitives and objects/instances with their own toString are fine, but regular methods and functions aren't? What about arrays, unknowns, anys, and type unions or intersections?

Let's discuss a bit to nail down how this should behave.

I was just looking for a rule for this. https://github.com/Microsoft/vscode/issues/68966

Meaning: primitives and objects/instances with their own toString are fine, but regular methods and functions aren't? What about arrays, unknowns, anys, and type unions or intersections?

Yes, I would want something specifically for functions and methods, (or type unions that could represent functions). I think that's the mistake that I'm most likely to make. It could also be useful for arrays, objects that don't have a non-default toString method, unknown etc.

Since TSLint migration to ESLint (medium post) and presence of this rule in eslint (no-implicit-coercion), I think it would be nice just to close this issue :) What do you think?

@ColCh there are still very many users on TSLint who rely on the features and/or rules that haven't yet been ported over to ESLint. Let's keep this issue open for the time being.

no-implicit-coercion also doesn't quite capture what this rule is proposed to do. Knowing whether something is a function requires type info, so it looks like that rule is a "weaker" form of this one.

Let's call this strict-string-expressions, to mirror strict-boolean-expressions

@JoshuaKGoldberg https://github.com/palantir/tslint/issues/4512#issuecomment-462049970 That makes things complicated :)

What about this example?

class Greeter {
    constructor(
        private name: string
    ) { }

    getGreetMsg() {
        return `Hello, ${this.name}!`;
    }

    toString() {
        return `Greeter for ${this.name}`;
    }
}

const greeter = new Greeter("World");

alert(`Result: ${greeter}`); // linter -> ERR or OK ?

I think, that in this case .toString() should be called too, like

alert(`Result: ${greeter.toString()}`); // linter -> OK

What about arrays, unknowns, anys, and type unions or intersections

hm, may be all things would require explicit String call but not string's

like

alert('test' + new Greeter()); // ERR
alert('test' + NeverTypeVar); // ERR
alert('test' + []); // ERR
alert('test' + { foo: 'foo' }); // ERR

// e.g. if x not typeof 'string', return ERR status

and pass only for strings

alert('test' + 'FOO'); // OK!

@ColCh yes, that makes sense & I agree. The simplest theology here makes sense: complex objects such as class instances and functions should have explicit .toString()s. 👍

Note: per #4534, this issue will be closed in less than a month if no PR is sent to add the rule. If you _really_ need the rule, custom rules are always an option and can be maintained outside this repo!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

denkomanceski picture denkomanceski  ·  3Comments

cateyes99 picture cateyes99  ·  3Comments

allbto picture allbto  ·  3Comments

Ne-Ne picture Ne-Ne  ·  3Comments

ypresto picture ypresto  ·  3Comments