-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Require "as const"? #47756
Comments
Is the underlying use case here the same as #30680? I would think you'd rather see type Specification = { readonly type: string; };
function SourceNode<T extends (string extends T["type"] ?
{ readonly type: "OH NOES YOU FORGOT as const" } : Specification)>(props: T) {
return { ...props }; // simplified to show a reduction.
};
export const BadStatement = SourceNode({
type: "Statement" // error, Type '"Statement"' is not assignable to type '"OH NOES YOU FORGOT as const"'.
});
export const Statement = SourceNode({
type: "Statement" // okay
} as const); I suppose if someone writes // I don't know, something like this
type Const<T> = T extends object ? { readonly [K in keyof T]: Const<T[K]> } :
T extends number ? number extends T ? 0 : T :
T extends string ? string extends T ? "" : T : T;
function foo<T>(x: Const<T>) { }
const oops = [123]
foo(oops) // error, number[] not assignable to readonly 0[]
const okay = [123] as const;
foo(okay) // okay |
I'm not 100% clear on what the thing being asked for is - if you wrote let s = "ok".
SourceNode({ type: s } as const); then the implicit contract is violated while the syntactic one is met. Conversely you could write const s: { type: "statement } = { type : "statement" };
SourceNode(s); and the implicit contract is met while the syntactic one is violated. Programming languages generally don't create constructs that forbid indirection - I don't think we'd ever add something that says that the syntactic form you pass to a function has to be a particular thing. Framework-specific linters do exist (e.g. React's hooks lint) and might be more appropriate. |
In some sense, I am kind of trying to write a syntax construct, and thus the lack of indirection would be fine, "the same way" you can't do
The responses above have actually been super helpful and given me plenty to experiment with. To get to the heart of the matter as to why I wouldn't just use a generic for this for example, is because it seems like any information I want to access both at runtime and type-check time needs to be expressed twice. I wish I could just treat exact strings kind of like in C++ templates: type SourceNode<Name extends exact string> = class
{
static type: Name = Name;
type: Name = Name;
}; However, I can't (to my knowledge) assign a value to the value of an exact string (nor can I assign types to static members of course). But if the above was possible, I could avoid having to do something like: class Statement extends SourceNode<"Statement">
{
static type = "Statement"; // Ugh.
type = "Statement";
} My workaround is to have a class factory that piggy-backs off of this sort of literal type inference to have my cake and eat it too: interface SourceNodeSpecification
{
type: string;
};
const SourceNode = (specification: SourceNodeSpecification) =>
class
{
static type = specification.type;
type = specification.type;
}; That way I can now do: const Statement = SourceNode
({
type: "Statement";
} as const);
function doStuff(node: Statement | Declaration)
{
if (statement.type === "Statement")
{
// Must be a Statement.
}
else
{
// Must be a Declaration.
}
} And then have all my nodes I instantiate have the correct type without having to pass in a string anywhere else in the program. |
@tolmasky function SourceNode<const T extends Specification>(props: T) {
return { ...props }; // simplified to show a reduction.
}; |
Suggestion
I have a factory function that takes a specification in the form of an object literal and returns a class. If the description passed in is a literal and annotated with
as const
, then the static properties it takes from the specification retain their exact types (like strings for instance), vs. the more generic "string" type:However, if you forget
as const
, all of this of course falls apart. I'd like a way to immediately surface an error if you don't pass anas const
object literal:I've tried every manner of annotation but haven't been able to accomplish this, but would love to know if there is a way to do this currently:
🔍 Search Terms
as const
, required, const annotation✅ Viability Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: