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

Improve support for Symbol.toPrimitive #4538

Open
weswigham opened this issue Aug 29, 2015 · 6 comments
Open

Improve support for Symbol.toPrimitive #4538

weswigham opened this issue Aug 29, 2015 · 6 comments
Labels
Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript

Comments

@weswigham
Copy link
Member

Presently, TS limits index types to 'string', 'number', 'symbol', or 'any'. That's fine, but consider the following:

class Foo {
    [Symbol.toPrimitive](): number {
        return 1;
    }
}

var x = ['a','b','c'];
var f = new Foo();
x[f];

We give the error an index expression argument must be of type ... on the array access.

Foo is for all intents and purposes a wrapper around the number 1 (close to new Number(1)), yet it cannot be used to index an array, since Foo itself is not of type number, string, symbol, or any. We could do extra type-checking to see if an object has a user-defined Symbol.toPrimitive and consider its return types when checking type-coercing operations (after all, if you've opted in to using Symbol.toPrimitve it's probably part of your goal to gain this behavior), such as indexing or mathematics operators.

Building on this, we currently don't support the coercion of Number or String classes to their respective primitive types (which are a specialization of the above issue but which applies to ES5 and ES3 output). Presently one can't do this:

function add(a: string, b: string): number {
  var x = new Number(a);
  var y = new Number(b);
  return x + y;
}
add('10e4', '0x8');

Because since neither x nor y is the 'number' (or 'string') primitive type, the addition operation is not allowed. Though it's still valid js (and without the usage of the Number class, the addition would result in '10e40x8'!).

@DickvdBrink
Copy link
Contributor

This is (imo) related to the valueOf method, so refs #2361

@weswigham
Copy link
Member Author

Aye, handling Symbol.toPrimitive would also have to deal with handling apparent types. Though no prior issues on the topic have specifically mentioned this new construct. It looks like we're looking for a spec proposal to cover this space...

@mhegazy mhegazy added Suggestion An idea for TypeScript Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. labels Aug 31, 2015
@icholy
Copy link

icholy commented Feb 3, 2017

@weswigham I've started working on a solution to this over in #2361

@bschlenk
Copy link

bschlenk commented Dec 5, 2020

I think this would make writing isomorphic packages that use setTimeout easier (#842). You'd be able to assign the Timeout type to a number.

@CMCDragonkai
Copy link

I thought I might try the hack where you intersect with a primitive. This works for alot of cases.

type Id = IdInternal & string;

class IdInternal {
  // psuedo code
  [Symbol.toPrimitive]() {
    return 'abc';
  }
}

const id = new IdInternal as Id;

const obj = {};
obj[id] = 3;

However I found that strings intersection results in conflicts with the main type. Especially in terms of index accessors:

// TS now thinks this is `never`
id[0]

So it would be nice to support some way of doing this. Although I noticed that Date has the same problem atm.

@flowerchaton
Copy link

class Vector {
    constructor(public y: number) { }
    [Symbol.toPrimitive](): number {
        return this.y;
    }
}
const v1 = new Vector(1);


console.log(`${v1 + v1}`);

The code works, but TypeScript does not allow it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

8 participants