Skip to content

Feature Request: const modifier on type parameters #46937

@shigma

Description

@shigma

Suggestion

🔍 Search Terms

const readonly modifier assertion immutable

✅ Viability 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, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

Generic functions in TypeScript automatically infer type parameters by its parameters, which is convenient and intelligent.

declare function foo<T>(value: T): T

foo({ a: 1 }) // { a: number }
foo([1, '2']) // (number | string)[]

Sometimes we want to get a more specific inference (asserting some value a is "constant" or "type immutable"):

foo({ a: 1 } as const) // { readonly a: 1 }
foo([1, '2'] as const) // readonly [1, '2']

However, some functions are designed to do such things, which means users should always add "as const" whenever they call it. Can we just place the constant asserting into function declaration?

📃 Motivating Example

declare function foo<T>(value: const T): T

foo({ a: 1 }) // { readonly a: 1 }
foo([1, '2']) // readonly [1, '2']

Alternative:

// use "readonly" instead of "const"
declare function foo<T>(value: readonly T): T

💻 Use Cases

It will be really useful for underlying libraries, such as schema validatation.

declare type Schema<T = any> = (value: T) => T

declare function number(): Schema<number>
declare function string(): Schema<string>

// case 1: tuple type

declare type TypeOf<S> = S extends Schema<infer T> ? T : never
declare type TupleOf<X extends readonly unknown[]> = X extends readonly [infer L, ...infer R] ? readonly [TypeOf<L>, ...TupleOf<R>] :[]

declare function tuple<X extends readonly Schema[]>(list: const X): Schema<TupleOf<X>>

tuple([number(), string()]) // Schema<readonly [number, string]>

// case 2: union type

declare function union<X extends Schema>(list: readonly X[]): Schema<TypeOf<X>>
declare function constant<T>(value: const T): Schema<T>

union([number(), string()]) // Schema<number | string>
union([constant(1), constant('2')]) // Schema<1 | '2'>

playground without suggested syntax

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions