Skip to content

Feature Request: const modifier on type parameters #46937

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
5 tasks done
shigma opened this issue Nov 28, 2021 · 6 comments
Closed
5 tasks done

Feature Request: const modifier on type parameters #46937

shigma opened this issue Nov 28, 2021 · 6 comments
Labels
Duplicate An existing issue was already created

Comments

@shigma
Copy link

shigma commented Nov 28, 2021

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

@shigma shigma changed the title Feature Request: const modifier Feature Request: const modifier on type parameters Nov 28, 2021
@jcalz
Copy link
Contributor

jcalz commented Nov 28, 2021

Duplicate of #30680?

@shigma
Copy link
Author

shigma commented Nov 28, 2021

Duplicate of #30680?

Thanks. I searched for relavant issues but I did not see this one. However the suggestion in #30680 is different.

@jcalz
Copy link
Contributor

jcalz commented Nov 28, 2021

I mean, it’s a little different, in that you are modifying the type parameter and the other one is modifying the constraint for the type parameter. But given that neither feature exists and both serve the same purpose (to cause inference of function arguments as if they were const-asserted by the caller), It’s probably reasonable to consider them β€œstrongly related” if not exact duplicates.

@RyanCavanaugh
Copy link
Member

This comes very close

declare function foo<T extends Record<string, unknown> | unknown[]>(value: T): Readonly<T>

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

But yes I believe the use cases here make this a duplicate

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Nov 29, 2021
@jcalz
Copy link
Contributor

jcalz commented Nov 29, 2021

@RyanCavanaugh I'm seeing readonly {a: number} and readonly (string | number)[] coming out of that. Am I missing something?

@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants