Skip to content

Feature Request: const modifier on type parametersΒ #46937

Closed
@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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions