镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

False or misleading errors with comparing the same types #15475

Description

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)

Activity

  1. blakeembrey commented on Apr 30, 2017

    @blakeembrey
    Contributor
    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>(...)).

  2. DanielRosenwasser commented on Apr 30, 2017

    @DanielRosenwasser
    Member

    Thanks for answering Blake Embrey (@blakeembrey)!

  3. zdrummond commented on May 2, 2017

    @zdrummond
    Author

    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?

  4. fatcerberus commented on May 2, 2017

    @fatcerberus

    Zachary Drummond (@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.

  5. zdrummond commented on May 2, 2017

    @zdrummond
    Author

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

    Daniel Rosenwasser (@DanielRosenwasser) Blake Embrey (@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!

  6. locked and limited conversation to collaborators on Jun 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions