microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.09k stars 12.5k forks source link

Unique type #59431

Open ruojianll opened 3 months ago

ruojianll commented 3 months ago

🔍 Search Terms

"unique type"

✅ Viability Checklist

⭐ Suggestion

Sometimes I just need a unique type as flags in my type calculations. If I use a string subtype or others it couldn't be identity well. Such as:

type Flag = 'Flag'
type MyType<T extends string|Flag>=T extends Flag? 'IsFlag':'A normal string'

In the code, Flag is also a string. I don't want to post some complex types which references each other and using flag types but it is really useful for me. Define a pure unique type without any runtime content.

📃 Motivating Example

type Flag1 = unique('Flag')
type Flag2 = unique('Flag')

Flag1 is not Flag2 like unique symbols. The unique types only extends itself for checking what it is. Pass a text to unique keyword to create a unique type.

💻 Use Cases

  1. What do you want to use this for? To control the type calculation especially in recursive type definitions.
  2. What shortcomings exist with current approaches? If I define a unique symbol, it should produce a runtime symbol.
  3. What workarounds are you using in the meantime? Write flag with string sub-type carefully.
jcalz commented 3 months ago

related #33038

ruojianll commented 3 months ago

@jcalz Shall we use it? Why was it closed?

nmain commented 3 months ago

See https://github.com/microsoft/TypeScript/issues/55691#issuecomment-1713748012

RyanCavanaugh commented 3 months ago
declare const _flag: unique symbol;
type Flag = typeof _flag;
type MyType<T extends string|Flag>=T extends Flag? 'IsFlag':'A normal string'
type M1 = MyType<"Flag">;
type M2 = MyType<Flag>;

Putting unique in type space quickly gets weird for a bunch of reasons because generic instantiation becomes a much different operation from a simple substitution, e.g. if you have

type Pair<T> = { x: T, y: T };

// __very__ different from writing { x: unique, y: unique }
type S = Pair<unique>;

This would mean many common identities would no longer be true

ruojianll commented 3 months ago
type S = Pair<unique>;

It has an error Type expected. @RyanCavanaugh

declare const _flag: unique symbol; means there is a unique symbol constant _flag in execution context, but no. This is not type safe.