Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

False or misleading errors with comparing the same types #15475

Closed
zdrummond opened this issue Apr 30, 2017 · 5 comments
Closed

False or misleading errors with comparing the same types #15475

zdrummond opened this issue Apr 30, 2017 · 5 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@zdrummond
Copy link

TypeScript Version: 2.3.1

Code

import * as _ from 'lodash'

var testObject = { 'a': [{ 'b': { 'c': 'boo' } }] };
if( _.get(testObject, 'a[0].b.c', 'foo') === 'boo') { //Error: TS2365
  let a = "boo" === "foo" //Error: TS2365
  let b = ("boo" as string) === "foo"
  let c = "foo" === "foo"

  console.log(`My results are a=${a}, b=${b} and c=${c}`)
}

Expected behavior:
No type related errors, and the resulting code outputs
> My values are a=false, b=false and c=true

Note: I would be fine if tsc produced errors (or better yet warned) about the no-op lines (all the lets) and let me know I was doing work for no reason. It does not do this

Actual behavior:
I get two errors both on the line listed above with the comment //Error: TS2365. The errors are

test.ts(4,5): error TS2365: Operator '===' cannot be applied to types '"foo"' and '"boo"'.  
test.ts(5,11): error TS2365: Operator '===' cannot be applied to types '"boo"' and '"foo"'.

I have three questions

  1. Why is the errors about types, when both sides are strings?
  2. Why does "foo" === "foo" work fine, but not "boo" === "foo"?
  3. Why does casting to string fix it?

and a bonus, why is lodash getting sucked into this. (note, the lodash is my actual production issue, the rest was just trying to explore the problem)

@blakeembrey
Copy link
Contributor

blakeembrey commented Apr 30, 2017

  1. The string is literal type
  2. Because the type of "foo" can only equal "foo" and never "boo"
  3. Casting to string treats it as a type of string instead of a string literal

You can enable noUnusedLocals to be warned when something is unused by the compiler. As for the _.get issue, check the signature of the method in the declaration file - it's possible it's using a generic and inferring "foo" but if that's wrong, you can override it to the type you want (something like _.get<string>(...)).

@DanielRosenwasser DanielRosenwasser added the Working as Intended The behavior described is the intended behavior; this is not a bug label Apr 30, 2017
@DanielRosenwasser
Copy link
Member

Thanks for answering @blakeembrey!

@zdrummond
Copy link
Author

zdrummond commented May 2, 2017

Thanks for the quick response!

So if I understand correctly, this is about boxing. As far as I could find, a "string literal" is a primitive and String is an object. And JS will auto-box the primitive when it needs to (i..e when it needs to call a function on a string for example).

So if we take the lodash get function with a default, I can imagine somewhere in there it might box the string, and in fact if I do as you suggest and add the <string> to get it works 👍

However, I don't understand is I am comparing to primitives, as I am in
let a = "boo" === "foo"
there should be no boxing, right? So, its not like the left is primative, and the right is an object, right? So it just return false and be done.

Also, with answer # 2, why does it matter if it's going to be always true, or always false? Why is true treated special?

@fatcerberus
Copy link

@zdrummond TypeScript has "literal types" for string, number and boolean, so that the type of a string literal "foo" is not actually string but literally "foo". In other words, this is a type error:

let a: "foo" = "foo";
a = "bar";  // type error

That's the cause of the errors you're seeing.

@zdrummond
Copy link
Author

@falsandtru Mind blown! It all clicks into place. Thanks for helping me understand.

@DanielRosenwasser @blakeembrey Thanks for your help as well! I really appreciate the core team helping with what really ends up being support.


I wonder if there is a way to make that more clear to newcomers. For example, Ruby linter has a nice description for each error, so you can understand the rational (random example https://github.com/bbatsov/ruby-style-guide#concat-strings).

I know a linter is different then a compiler, but it feels like if there was a link-out to common issues it would be really nice. To that point, y'all put an error number (in this case TS2365) on it, but Google only finds Github Issues and Stack Overflow response; if there are docs or more details they are hard to find.

Thanks again!

@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

5 participants