Feature Request: const modifier on type parameters ยท Issue #46937 ยท microsoft/TypeScript (original) (raw)
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(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(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(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 declare function string(): Schema
// case 1: tuple type
declare type TypeOf = S extends Schema ? T : never
declare type TupleOf<X extends readonly unknown[]> = X extends readonly [infer L, ...infer R] ? readonly [TypeOf, ...TupleOf] :[]
declare function tuple<X extends readonly Schema[]>(list: const X): Schema<TupleOf>
tuple([number(), string()]) // Schema<readonly [number, string]>
// case 2: union type
declare function union(list: readonly X[]): Schema<TypeOf> declare function constant(value: const T): Schema
union([number(), string()]) // Schema<number | string> union([constant(1), constant('2')]) // Schema<1 | '2'>