Description
Suggestion
In userland code, you can use as const
, but as a library author, I often want to provide the best possible experience, and when there's an opportunity for a literal value to be produced, I would like to infer that value for my users without them having to use (or remember to use) as const
.
🔍 Search Terms
constant literals, Math.random, require as const, infer literals, readonly by default
✅ 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
Provide an ability to narrow types at the type level (i.e. without JavaScript where you can use as const
).
📃 Motivating Example
const notLiteral = () => "A";
A type like this produces () => string
. I can improve the situation by specifying as const
, which will cause it to produce () => "A"
.
Note: I'm not totally sure how related this is, but I've seen
> () => Math.random() > 0.5 ? "A" : "B"
which produces() => "A" | "B"
, and it's not clear to me what the difference is from the example above
However, in the context of a library, a library author doesn't have the option to do this in the type level. Something for this use-case would be a nice improvement:
////// LIBRARY CODE
const UploadThingServerHelper = <ValidRoutes,>(
route: {
readonly [Route in keyof ValidRoutes]: {
middleware: () => ValidRoutes[Route]; // how can a library author force a more specific type here?
onUpload: (response: { metadata: ValidRoutes[Route] }) => void;
};
}
) => {};
////// END USER CODE
const FileRouter = UploadThingServerHelper({
example: {
middleware: () => "someValue", // and end-user must remember to put `as const` here to force it to return a literal
onUpload: response => {
response.metadata; // the result is that the type here is not as narrow as it could be for the best user experience
// ^?
},
},
});
💻 Use Cases
This is useful for libraries trying to provide a great user experience with great inferencing. It should be a backwards compatible change. There are no workarounds that I'm aware of (from the code of a library).