Skip to content

Cannot return unique symbol #32242

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

Closed
AnyhowStep opened this issue Jul 3, 2019 · 7 comments
Closed

Cannot return unique symbol #32242

AnyhowStep opened this issue Jul 3, 2019 · 7 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@AnyhowStep
Copy link
Contributor

TypeScript Version: 3.5.1

Search Terms:

function, return type, unique symbol

Code

const a = Symbol();
const b = Symbol();

function identity<T> (t : T) : T {
  return t;
}

/**
 * Mouseover `identity(a)`,
 * Tooltip shows,
 * 
 * ```
 * function identity<typeof a>(t: typeof a): typeof a
 * ```
 */
/**
 * Expected : typeof a
 * 
 * Actual   : symbol
 */
const actual = identity(a);
/**
 * Error
 * 
 * Type 'symbol' is not assignable to type 'unique symbol'.
 */
const expectA : typeof a = actual;

/////////////////////////////////////////////////

function giveTypeOfA () : typeof a {
  return a;
}

/**
 * Expected : typeof a
 * 
 * Actual   : symbol
 */
const actual2 = giveTypeOfA();
/**
 * Error
 * 
 * Type 'symbol' is not assignable to type 'unique symbol'.
 */
const expectA2 : typeof a = actual2;

Expected behavior:

actual and actual2 should be typeof a

Actual behavior:

actual and actual2 are symbol

Playground Link: Playground

Related Issues:

The very last comment of #24506 asks a question about intended behaviour but it goes unanswered.

@AnyhowStep
Copy link
Contributor Author

AnyhowStep commented Jul 3, 2019

The current workaround is,

const a = Symbol();

function giveTypeOfA () : { workaround : typeof a } {
  return { workaround : a };
}

/**
 * Expected : { workaround : typeof a }
 * 
 * Actual   : { workaround : typeof a }
 */
const actual2 = giveTypeOfA();
/**
 * Assignment OK!
 */
const expectA2 : typeof a = actual2.workaround;

Playground


Returning a tuple with one element also works,

const a = Symbol();

function giveTypeOfA () : [typeof a] {
  return [a];
}

/**
 * Expected : [typeof a]
 * 
 * Actual   : [typeof a]
 */
const actual2 = giveTypeOfA();
/**
 * Assignment OK!
 */
const expectA2 : typeof a = actual2[0];

Playground


However, this does not work,

const a = Symbol();

function giveTypeOfA () : [typeof a] {
  return [a];
}

/**
 * Expected : typeof a
 * 
 * Actual   : symbol
 */
const actual2 = giveTypeOfA()[0];
/**
 * Assignment Not allowed
 */
const expectA2 : typeof a = actual2;

Playground


So, it seems like I have to "box" the unique symbol until I actually need it.

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jul 26, 2019
@RyanCavanaugh
Copy link
Member

The uniqueness of a symbol goes away through widening.

@AnyhowStep
Copy link
Contributor Author

Why would it widen for foo () : typeof a but not foo() : [typeof a]?

@typescript-bot
Copy link
Collaborator

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@artalar
Copy link

artalar commented Aug 15, 2019

Sorry, but Im really "Cannot return unique symbol":

function getSymbol() {
  const uniqueSymbol: unique symbol = Symbol()
  return uniqueSymbol
}

var a = getSymbol()
// no error??
var b: typeof a = getSymbol()

@coreh
Copy link

coreh commented Feb 20, 2020

I know this ticket is closed and marked as "Working as Intended", but IMO the current behavior makes it a bit harder than necessary to create custom Unit types that are guaranteed to not clash with string/number literals and "survive" being passed through generic function calls without getting widened to just symbol.

I'm using @AnyhowStep's tuple "boxing" workaround for now (thanks for pointing that out!) but I would like to ask if y'all could reconsider, and change the unique symbol widening behavior to be the same as the one used for string/number literals.

I'm not sure if doing so could have additional implications to the type system... (Maybe something breaks because of it?) In that case, perhaps we could maybe opt out of the widening behavior via the unique type modifier?

function identity<T> (t : T) : unique T {
  return t;
}

@RyanCavanaugh
Copy link
Member

It's confusing to allow this because it's unclear if : unique T means "Returns the same unique symbol each time" or "Returns a new unique symbol each time".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
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