Repository: TypeScript
Issue: Symbol definition improvement
Labels: Suggestion,In Discussion

<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨

Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker. Please read the FAQ first, especially the "Common Feature Requests" section.

-->

## Search Terms

<!-- List of keywords you searched for before creating this issue. Write them down here so that others can find this suggestion more easily -->
symbol in:title, symbol improvement, symbol description definition

## Suggestion

By using more and more `symbol` in my projects, and to make debugging easier in development mode, I fill the optional description to Symbol. Then, on production, I remove all description during the bundling process:
![image](https://user-images.githubusercontent.com/5469433/54876463-c9eeb200-4e29-11e9-8ac9-28f98e25bf5c.png)

So I was thinking that it could be really useful to have the same approach for TypeScript - [playground](https://www.typescriptlang.org/play/#src=type%20xsymbol%3CT%3E%20%3D%20%7B%7D%3B%0D%0A%0D%0Ainterface%20xSymbolConstructor%20%7B%0D%0A%20%20%20%20()%3A%20symbol%3B%0D%0A%20%20%20%20%3CT%20extends%20string%20%7C%20number%3E(description%3A%20T)%3A%20xsymbol%3CT%3E%3B%0D%0A%7D%0D%0A%0D%0Avar%20xSymbol%3A%20xSymbolConstructor%3B%0D%0A%0D%0Avar%20s1%20%3D%20xSymbol()%3B%0D%0Avar%20s2%20%3D%20xSymbol(%22test%22)%3B):
![image](https://user-images.githubusercontent.com/5469433/54876631-703bb700-4e2c-11e9-8b17-1fc22d634f6a.png)
![image](https://user-images.githubusercontent.com/5469433/54876634-76ca2e80-4e2c-11e9-861c-bd2da7bb6368.png)

Just imagine we don't have `xsymbol<"test">` but the "native" `symbol<"test">` or `symbol("test")` to be closer to DevTools.

Then, by extending this approach, I don't know if it could be helpful to increase the typing inference.
Given this code:
```ts
const foo = {
    type: 'foo' as 'foo',
    foo: ''
};

const bar = {
    type: 'bar' as 'bar',
    bar: ''
};

type FooBarAction = typeof foo | typeof bar;

function getType<T>(input: {type: T}): T {
    return input.type;
}

function foobar(action: FooBarAction) {
    switch (action.type) {
        case getType(foo):
            action.foo;
            break;
        case getType(bar):
            action.bar;
            break;
    }
}
```
![image](https://user-images.githubusercontent.com/5469433/54876698-aa598880-4e2d-11e9-8427-1f5024ae3f4a.png)

Here, according to the `type` property value, the `action` provide correctly `foo` property or `bar` property.

But, if I replace them by `symbol`:
```ts
const sFoo = {
    type: Symbol('sfoo'),
    sfoo: ''
};

const sBar = {
    type: Symbol('sbar'),
    sbar: ''
};

type SFooBarAction = typeof sFoo | typeof sBar;

function sfoobar(action: SFooBarAction) {
    switch (action.type) {
        case getType(sFoo):
            action.sfoo;
            break;
        case getType(sBar):
            action.sbar;
            break;
    }
}
```
![image](https://user-images.githubusercontent.com/5469433/54876707-c3fad000-4e2d-11e9-90d6-d05505d8b849.png)
![image](https://user-images.githubusercontent.com/5469433/54876717-e391f880-4e2d-11e9-8962-f08e3be0e3cf.png)

Here TypeScript cannot resolve properly the correct definition of my `action` variable and keep saying that it get the `SFooBarAction` type, so only `type` property is available.

According to this PR #30196, I understand that working on `symbol` in the core system of TypeScript is not an easy thing, but probably it could be helpful if the optional `description` of `Symbol` as a definition descriptor to have the unique symbol in the definition. But definitely, as soon as we provide same `description`, we will face the same problem as today.

[Full Playground](https://www.typescriptlang.org/play/#src=type%20xsymbol%3CT%3E%20%3D%20%7B%7D%3B%0D%0A%0D%0Ainterface%20xSymbolConstructor%20%7B%0D%0A%20%20%20%20()%3A%20symbol%3B%0D%0A%20%20%20%20%3CT%20extends%20string%20%7C%20number%3E(description%3A%20T)%3A%20xsymbol%3CT%3E%3B%0D%0A%7D%0D%0A%0D%0Avar%20xSymbol%3A%20xSymbolConstructor%3B%0D%0A%0D%0Avar%20s1%20%3D%20xSymbol()%3B%0D%0Avar%20s2%20%3D%20xSymbol(%22test%22)%3B%0D%0A%0D%0Aconst%20foo%20%3D%20%7B%0D%0A%20%20%20%20type%3A%20'foo'%20as%20'foo'%2C%0D%0A%20%20%20%20foo%3A%20''%0D%0A%7D%3B%0D%0A%0D%0Aconst%20bar%20%3D%20%7B%0D%0A%20%20%20%20type%3A%20'bar'%20as%20'bar'%2C%0D%0A%20%20%20%20bar%3A%20''%0D%0A%7D%3B%0D%0A%0D%0Atype%20FooBarAction%20%3D%20typeof%20foo%20%7C%20typeof%20bar%3B%0D%0A%0D%0Afunction%20getType%3CT%3E(input%3A%20%7Btype%3A%20T%7D)%3A%20T%20%7B%0D%0A%20%20%20%20return%20input.type%3B%0D%0A%7D%0D%0A%0D%0Afunction%20foobar(action%3A%20FooBarAction)%20%7B%0D%0A%20%20%20%20switch%20(action.type)%20%7B%0D%0A%20%20%20%20%20%20%20%20case%20getType(foo)%3A%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20action.foo%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0D%0A%20%20%20%20%20%20%20%20case%20getType(bar)%3A%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20action.bar%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0Aconst%20sFoo%20%3D%20%7B%0D%0A%20%20%20%20type%3A%20Symbol('sfoo')%2C%0D%0A%20%20%20%20sfoo%3A%20''%0D%0A%7D%3B%0D%0A%0D%0Aconst%20sBar%20%3D%20%7B%0D%0A%20%20%20%20type%3A%20Symbol('sbar')%2C%0D%0A%20%20%20%20sbar%3A%20''%0D%0A%7D%3B%0D%0A%0D%0Atype%20SFooBarAction%20%3D%20typeof%20sFoo%20%7C%20typeof%20sBar%3B%0D%0A%0D%0Afunction%20sfoobar(action%3A%20SFooBarAction)%20%7B%0D%0A%20%20%20%20switch%20(action.type)%20%7B%0D%0A%20%20%20%20%20%20%20%20case%20getType(sFoo)%3A%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20action.sfoo%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0D%0A%20%20%20%20%20%20%20%20case%20getType(sBar)%3A%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20action.sbar%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0A%0D%0Aconst%20xFoo%20%3D%20%7B%0D%0A%20%20%20%20type%3A%20xSymbol('sfoo')%2C%0D%0A%20%20%20%20xfoo%3A%20''%0D%0A%7D%3B%0D%0A%0D%0Aconst%20xBar%20%3D%20%7B%0D%0A%20%20%20%20type%3A%20xSymbol('sbar')%2C%0D%0A%20%20%20%20xbar%3A%20''%0D%0A%7D%3B%0D%0A%0D%0Atype%20XFooBarAction%20%3D%20typeof%20xFoo%20%7C%20typeof%20xBar%3B%0D%0A%0D%0Afunction%20xfoobar(action%3A%20XFooBarAction)%20%7B%0D%0A%20%20%20%20switch%20(action.type)%20%7B%0D%0A%20%20%20%20%20%20%20%20case%20getType(xFoo)%3A%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20action.xfoo%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0D%0A%20%20%20%20%20%20%20%20case%20getType(xBar)%3A%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20action.xbar%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A)

## Use Cases

For the first part, everywhere when we use `Symbol`.

For the second part, as soon as unique value is required, like for `Event Emitter`, `Action` in `Redux` architecture, ...

## Examples

See above on the `Suggestion` section

## Checklist

My suggestion meets these guidelines:

* [ ] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
* [ ] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).