Skip to content

unique symbol incorrectly widens to symbol when assigning to a const or readonly property #23263

@kpdonn

Description

@kpdonn

Search Terms:
unique symbol, literal, widen, reassign, const, readonly

Code

const t1 = Symbol("t1")
const t1Copy = t1
const result1: typeof t1 = t1 // no error
const result2: typeof t1 = t1Copy // error: type symbol not assignable to unique symbol

class T2 {
    static readonly sym = Symbol("T2")
    readonly kind = T2.sym
}

const inst = new T2()
const result3: typeof T2.sym = T2.sym // no error
const result4: typeof T2.sym = inst.kind // error: type symbol not assignable to unique symbol

declare function genericIdentity<T>(arg: T): T
const unexpectedError: typeof t1 = genericIdentity(t1)

declare function genericSymbolNested<T extends symbol>(arg: T): { prop: T }
const unexpectedError2: { prop: typeof t1 } = genericSymbolNested(t1)

Expected behavior:
No errors. t1Copy and inst.kind should retain their respective literal unique symbol types the same way string literals would because they are declared with const and readonly.

Actual behavior:
Errors on result2 and result4 because t1Copy and inst.kind are widened to symbol. When assigning a unique symbol variable to a new variable the type is always widened to symbol unless an explicit type annotation is added.

Playground Link:
Link

Related Issues:
Did not notice any similar bug reports, but the design notes from #17501 seem to confirm that the current behavior is a bug:

  • Like literal types, these types contain "freshness" which can be widened away to produce a "regular" type.
  • When you alias a symbolic const with another const, it has the type typeof [[that original variable]].

Which implies they should work like other literal types which would not be widened in the example above.

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