Skip to content
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

const string or const number as a type between string (or number) and literal types #51745

Closed
5 tasks done
zen0wu opened this issue Dec 4, 2022 · 4 comments
Closed
5 tasks done
Labels
Duplicate An existing issue was already created

Comments

@zen0wu
Copy link

zen0wu commented Dec 4, 2022

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) // passes

The 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
@fatcerberus
Copy link

Looks like a duplicate of #51513

@zen0wu
Copy link
Author

zen0wu commented Dec 4, 2022

True. Mine's syntax is a bit more inclusive with the support of const ??? and const string[], but the crux is the same.

@zen0wu
Copy link
Author

zen0wu commented Dec 4, 2022

Almost exactly like what #41114 is proposing :)

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Dec 5, 2022
@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