Skip to content

Support Const Type Constraint #41114

Closed

Description

Search Terms

Const Type Constraint Literal

Suggestion

Add new syntax const T or a global generic type Constant<T = any> = T extends const T ? T : never;

type ConstString = const string is same as type ConstString = Constant<string>.

  • If T extends string | number | boolean | symbol | bigint | null | undefined, requires T to be a constant.
  • If T is object or Array, requires every member of T to be a constant.
  • If T is enum, nothing to do, because enum is same as const enum

The difference with union literal is that type 'foo' | 'bar' can only be 'foo' or 'bar', but type const string can be any constant string.

Use Cases

  • Sometimes we want to constrain a type or a parameter to be literal.
  • It can help the TS compiler to recognize constant types better

Examples

let foo = 'foo'; // string
const bar= 'bar'; // 'bar'

const notConstant: const string = foo; // error
const trulyConstant: const string = bar; // success

type Baz = { baz: string } ;
const baz1: const Baz = { baz: 'baz' }; // success
const baz2: Baz = { baz: 'baz' }; // not a constant
const baz3: Baz  = { baz: 'baz' } as const; // current available, same as baz1

type ConstArray<T> = const Array<T>;
// same as
type AnotherCosntArray<T> = Array<const T>;

function tuple<T extends ConstArray>(...args: T) {
  return args;
}
const t1 = tuple(foo); // error!
const t2 = tuple(bar); // success! typeof t2 should be ['bar']
const t3 = tuple('a', 1, true, ['1'], baz1) // ['a', 1, true, ['1'], { baz: 'baz' }];
const t4 = tuple(baz2) // error!

let variable: const string = 'variable'; // this is possible
variable = 'another variable'; // success
variable = document.title; // error

let reactiveObject: const { foo: string } = { foo: 'foo' }; // success;
reactiveObject.foo = 'bar' // success

In fact, const only affects the assignment behavior, and a const type is considered to be the same as a non const type when read it.
A const type doesn't mean immutable, just means every primitive value should be literal, so maybe should call it literal type.

Alternatives

  • Only add extends const syntax, and add global generic type Constant<T = any> = T extends const ? T : never;
  • Use finally or static or literal(not exist in current keywords) keyword instead of const
  • Use type Literal instead of type Constant.

Related issues

#30680 Suggestion: Const contexts for generic type inference

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions