Typescript: Boolean["toString"] inconsistency

Created on 5 Mar 2019  路  10Comments  路  Source: microsoft/TypeScript

TypeScript Version: 3.4.0-dev.20190305

Code

const key: keyof Boolean = "toString"; // error - "toString" is not assignable to "valueOf"

const x: {toString(): string} = new Boolean(); // no error
const y: Boolean["toString"] = true.toString; // no error

class Bool extends Boolean { 
     protected toString() { // also no error, but should be
          return "";
     }
}

Expected behavior:
keyof Boolean should be "toString" | "valueOf"
Playground

In Discussion Suggestion

Most helpful comment

Abbreviated summary: we're using the TypeScript type system to transform calls of the form x.toString() into AppropriateClass.prototype.toString.call(x). Without accurate information about the methods in x's prototype chain, this is not possible.

In general, anything which is relying on the TypeScript definitions giving an accurate summary of what methods a class has will encounter this problem.

All 10 comments

Apparent properties (such as toString) intentionally aren't included in keyof or inheritance validity checks, so some inconsistencies between keyof and property access is expected and intentional.

I think we could safely add toString to interface Boolean, though I am extremely curious how you came to notice this in the first place.

@RyanCavanaugh you wrong. keyof of any other type includes toString. For example: keyof Number, keyof String. even keyof Symbol

you wrong. keyof of any other type

No, I right.

interface Foo { m; }
// Error
const k: keyof Foo = "toString";

Unlike Boolean, Number, String, and Symbol have explicitly-declared toString methods in their corresponding interface, which is why toString is in their keyofs, which is why I proposed adding toString to Boolean's interface.

@RyanCavanaugh ok. so the same problem with RegExp, Date, ... And now there is inconsistency:
image
playground

@jacksteinberg and I have noticed this in a project that is using the TypeScript definitions. We have so far identified the following missing declarations:

In contrast, others overrides of Object.prototype methods are included in the TypeScript definitions, e.g. Number.prototype.toString, Boolean.prototype.valueOf, Array.prototype.toLocaleString.

We haven't done an exhaustive search; those were just particular instances of overridden toStrings that we were trying to pick up with our tool (but ended up getting the wrong result due to the missing TypeScript definitions). In particular I wonder if other stringifiers in Web IDL interfaces are not being picked up correctly.

/cc @saschanaz as someone who has been helpful keeping TypeScript's built-in type definitions up to date in the past.

Corresponding issue on TSJS-lib-generator: https://github.com/microsoft/TSJS-lib-generator/issues/322.

The emitter currently does not do anything for stringifier and only provides the inherited toString.

We could generate toString for every interfaces but that would be a big noise and duplication, maybe we should just include toString in keyof?

I think it'd be best to include toString for the interfaces which have specific toString behavior that differs from Object.prototype. There are not many of those. (I'd guess 5 in the JS spec, 20ish on the web platform.)

This already seems to be the policy, e.g. Array.prototype.toString and Number.prototype.toString are included. There are just some that got missed for whatever reason.

I think it'd be best to include toString for the interfaces which have specific toString behavior that differs from Object.prototype.

Definitely can be done, but what would be the use cases? Couldn't understand the purpose of https://github.com/jackbsteinberg/get-originals-rewriter/issues/79.

Abbreviated summary: we're using the TypeScript type system to transform calls of the form x.toString() into AppropriateClass.prototype.toString.call(x). Without accurate information about the methods in x's prototype chain, this is not possible.

In general, anything which is relying on the TypeScript definitions giving an accurate summary of what methods a class has will encounter this problem.

Object.prototype.toString is a native function that returns '[object Object]'. So shouldn't be errors like

  • Type '{ toString: () => string; }' is not assignable to type 'string'

because it is JS core feature.
PS And we didn't start to talk about Symbol.toPrimitive

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DanielRosenwasser picture DanielRosenwasser  路  3Comments

jbondc picture jbondc  路  3Comments

Antony-Jones picture Antony-Jones  路  3Comments

Roam-Cooper picture Roam-Cooper  路  3Comments

siddjain picture siddjain  路  3Comments