const string or const number as a type between string (or number) and literal types #51745
Copy link
Copy link
Closed
Closed
Copy link
Labels
DuplicateAn existing issue was already createdAn existing issue was already created
Description
Suggestion
🔍 Search Terms
literal string, const literals, infer literals
✅ 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
const x: const string = "abc" // passes
const y = "adsf" as string
const y2: const string = y // fails
function f<T extends const string>(t: T) {}
const x = 'abc' as const
f(x) // passes
f(x as string) // error
function f<T extends const string[]>(...t: T) {}
const xs = ["a", "b", "c"]
f(...xs) // passes
f(...xs as ["a", string, "c"]) // fails
function f<T extends [string, const string]>(...t: T) {}
const a = "a"
const s = some_str
f(a, s) // fails
f(s, a) // passesThe same applies to numbers.
📃 Motivating Example
I want to define an API for users to specify a fixed path in an object, consider
type Obj = {
a: {
b: {
c: "123"
}
}
}
type Get<T, K> = K extends keyof T ? NonNullable<T[K]> : never
type GetPath<T, P> = P extends PathKey[]
? P extends []
? T // If P is empty, return T.
: P extends [infer K, ...infer Rest]
? GetPath<Get<T, K>, Rest> // Else, recurse.
: never
: never
function set<T, P extends string[]>(obj: T, path: P, value: GetPath<T, P>) {}
set(
obj,
["a", "b", "c"],
value
)Currently, typescript would infer this set call's P as string[], hence value will be inferred as never.
This however, works when P extends string, so one way of doing this would be
function set<T, P extends string>(obj: T, path: [P], value: unknown) {}
function set<T, P1 extends string, P2 extends string>(obj: T, path: [P1, P2], value: unknown) {}
function set<T, P1 extends string, P2 extends string, P3 extends string>(obj: T, path: [P1, P2, P3], value: unknown) {}
// ...This feels both cumbersome and not scalable.
With the proposed change, it'll look like
funciton set<T, P extends const string[]>(obj: T, path: P, value: GetPath<T, P> {}On the other hand, sometimes people do want their generics to be inferred as string, not the literal passed in.
Allowing a const bound would allow developers to express precisely what they want.
💻 Use Cases
- Enforce string or number literal types for generics, hence forbidding generic strings/numbers passed in
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
DuplicateAn existing issue was already createdAn existing issue was already created
Activity
fatcerberus commentedon Dec 4, 2022
Looks like a duplicate of #51513
zen0wu commentedon Dec 4, 2022
True. Mine's syntax is a bit more inclusive with the support of
const ???andconst string[], but the crux is the same.zen0wu commentedon Dec 4, 2022
Almost exactly like what #41114 is proposing :)
typescript-bot commentedon Dec 8, 2022
This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.