You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Feature Request] Add a strong typed struct/class that cannot assign a new field that is not defined in the struct/class. #1990
I'd like to see this too. I'm in favour of struct because it's similar to C#, but exact works fine too. I'm also liking other suggestions for built-in types like Exact<MyClass> instead of more @ styled notation because that might enable support for future features with a more modular approach.
For example, ReadOnly<T> could then also be added to change the behaviour of the wrapped generic type T where T is a collection data type (e.g., a table or list) to tell LuaLS that its read-only, or Callable<MyTable> might be good for declaring that a table has the __call meta-method so you can call it like a function. Who knows 🤷 but it sounds interesting.
Really need this feature (for one, it catches typos). It shouldn't be too hard to implement?
Referencing an undefined variable emits an LSP error or warning (even regardless of the fact that it is not a runtime error to do so) and this is a good thing, so why wouldn't the same hold true for table indices?
IIRC, typescript disallows extra keys by default (or maybe it's opt-in behavior to have it that way, I don't remember), and then you can allow additional arbitrary keys on a type by it defining/declaring like this:
I don't think this is totally necessary however. A special symbol, type constructor, or additional annotation (kinda like @field is its own annotation and goes on its own line) would suffice (whether it's Freeze<> or Exact<> or ---@exact or whatever else).
An exact table for the input of functions is also something I would also be very interested in! Initially I was just using params everywhere for function input definitions, but wanted to switch over to using exact dicts as the input to functions utilizing @Class, as I thought it made the code cleaner (especially in places where the arguments in should be 'nested').
One thing I would like to see though if this every makes it in, is the possibility to mark fields on classes as optional using the normal ? syntax. When using the @Class I want to require some fields, allow but not require some other fields, and disallow everything else
I know it'll break existing code and require work to update the definitions everywhere, but would you consider simply changing the existing @class so that it enforces exactness by default? If a user wants to opt out for certain fields, they'll have to manually annotate them as having nil values:
---@fieldstudy_level? integer-- or this, but I prefer the first syntax:---@fieldstudy_levelinteger?
This is how TypeScript works and while Lua annotations and TypeScript are different, I think enforcing types to be exact by default is a more consistent design that forces the user to think about class fields and whether they should be required or optional.
Of course, I understand the amount of headache involved in updating large codebases and addon libraries, but I thought it's worth mentioning this option if you want to consider it for a future major version.
Reacted by Lewis Russell, Tyler Miller and Bas van den Wollenberg
I know it'll break existing code and require work to update the definitions everywhere, but would you consider simply changing the existing so that it enforces exactness by default? If a user wants to opt out for certain fields, they'll have to manually annotate them as having nil values:@class
---@fieldstudy_level? integer-- or this, but I prefer the first syntax:---@fieldstudy_levelinteger?
This is how TypeScript works and while Lua annotations and TypeScript are different, I think enforcing types to be exact by default is a more consistent design that forces the user to think about class fields and whether they should be required or optional.
Of course, I understand the amount of headache involved in updating large codebases and addon libraries, but I thought it's worth mentioning this option if you want to consider it for a future major version.
No, because many users will declare fields using a mixed approach, for example:
---@classMyClass---@fieldidintegerlocalM=Class'MyClass'M.showName='MyClass'functionM:init()
self.list= {}
self.id=nextID()
end
No, because many users will declare fields using a mixed approach, for example:
---@classMyClass---@fieldidintegerlocalM=Class'MyClass'M.showName='MyClass'functionM:init()
self.list= {}
self.id=nextID()
end
(Translated by ChatGPT)
In that case the explicitly set fields are not optional unless they're nil-able, or do you meant that it's technically complex to implement?
Anyway it's just an idea if you want to consider a stricter and more consistent type system instead of adding more special keywords. One thing I notice with the language server is that because users (myself included) ask for a lot of orthogonal features, and there is usually one implementer, the annotations start to get more complex and more inconsistencies can arise.
To be clear, I think you're doing a great job managing all this complexity and carefully reviewing suggestions, but I bring up TypeScript because it's a mature language that went through some similar discussions, and the result is a more consistent and strict model that catches many user errors.
I know that I'm probably not thinking of a lot of the other use cases where my idea won't work. Having any kind of @exact annotation would still be extremely helpful. (I prefer ---@class Student <exact> in your example, assuming there will be new kinds of 'attributes' added to classes in the future)
I can try adding an option that is enabled by default to enable this feature. If many users give feedback that they don't like this feature, I can downgrade it to default disable and provide new annotations to manually mark it.
(Translated by ChatGPT)
Reacted by Firas Assaad, Lewis Russell, Tyler Miller, GiuseppeIII and Bas van den Wollenberg
I can try adding an option that is enabled by default to enable this feature. If many users give feedback that they don't like this feature, I can downgrade it to default disable and provide new annotations to manually mark it.
(Translated by ChatGPT)
That's a good compromise. I assume it'll still be in a new major version (4?) because I know this will break most of my existing code 😅
You can also make a separate pinned issue to announce this change and solicit more user feedback before doing it, like you did for some features in the past. That way more users will see it coming, at least.
It's also worth mentioning that TypeScript provides a Partial<className> syntax for cases where you want to opt-out of exact types and tell the compiler that all the fields are optional:
interfacePerson{name:string;address:stringage:number}letperson:Partial<Person>={}//No error. All Properties are now optional in person object
Edit: I'd argue that defining things on self inside functions isn't really part of the class definition and your approach loses some valuable warnings by treating it the same as m
My approach doesn't treat self as part of the class definition.
@sumneko Thank you so much for implementing this. It already helped me spot some issues in my code.
Is it possible to emit a warning when a table is defined here (when setting w = 2):
---@class (exact) Class---@fieldxinteger---@typeClasslocaly= {
x=1, -- Finew=2, -- Should warn, but doesn't?
}
y.x=2-- Finey.z=4-- Warning! Works as expected
Also for nested cases:
---@classAnother---@fieldcClass---@typeAnotherlocala= {
c= {
x=1,
w=4, -- Currently there are no warnings
}
}
Let me know if you prefer that I open another issue for this.
Edit: the issue is probably the same as this one: #2288
In these cases it works, however in the case of ---@type it seems not. It's weird but it makes sense that it would work, or maybe not? I hope some expert on the subject has something to say.
Activity
firas-assaad commentedon Mar 9, 2023
Similar previous discussions:
@classfields is incomplete/inconsistent #1823Mayron commentedon Apr 7, 2023
I'd like to see this too. I'm in favour of
structbecause it's similar to C#, butexactworks fine too. I'm also liking other suggestions for built-in types likeExact<MyClass>instead of more@styled notation because that might enable support for future features with a more modular approach.For example,
ReadOnly<T>could then also be added to change the behaviour of the wrapped generic type T where T is a collection data type (e.g., a table or list) to tell LuaLS that its read-only, orCallable<MyTable>might be good for declaring that a table has the__callmeta-method so you can call it like a function. Who knows 🤷 but it sounds interesting.Calandiel commentedon Apr 24, 2023
Would you accept PRs regarding this or is this subject completely off the table?
sumneko commentedon Apr 24, 2023
I'm glad to accept PRs.
tmillr commentedon May 18, 2023
Really need this feature (for one, it catches typos). It shouldn't be too hard to implement?
Referencing an undefined variable emits an LSP error or warning (even regardless of the fact that it is not a runtime error to do so) and this is a good thing, so why wouldn't the same hold true for table indices?
IIRC, typescript disallows extra keys by default (or maybe it's opt-in behavior to have it that way, I don't remember), and then you can allow additional arbitrary keys on a type by it defining/declaring like this:
instead of like this:
I don't think this is totally necessary however. A special symbol, type constructor, or additional annotation (kinda like
@fieldis its own annotation and goes on its own line) would suffice (whether it'sFreeze<>orExact<>or---@exactor whatever else).GiuseppeIII commentedon May 29, 2023
An exact table for the input of functions is also something I would also be very interested in! Initially I was just using params everywhere for function input definitions, but wanted to switch over to using exact dicts as the input to functions utilizing @Class, as I thought it made the code cleaner (especially in places where the arguments in should be 'nested').
One thing I would like to see though if this every makes it in, is the possibility to mark fields on classes as optional using the normal
?syntax. When using the @Class I want to require some fields, allow but not require some other fields, and disallow everything elsesumneko commentedon May 31, 2023
My current idea is
or
Any other good ideas are also welcome.
(Translated by ChatGPT)
firas-assaad commentedon May 31, 2023
I know it'll break existing code and require work to update the definitions everywhere, but would you consider simply changing the existing
@classso that it enforces exactness by default? If a user wants to opt out for certain fields, they'll have to manually annotate them as having nil values:This is how TypeScript works and while Lua annotations and TypeScript are different, I think enforcing types to be exact by default is a more consistent design that forces the user to think about class fields and whether they should be required or optional.
Of course, I understand the amount of headache involved in updating large codebases and addon libraries, but I thought it's worth mentioning this option if you want to consider it for a future major version.
lewis6991 commentedon May 31, 2023
I agree with @firas-assaad . As a compromise this could be enabled by default when only strict is enabled
sumneko commentedon May 31, 2023
No, because many users will declare fields using a mixed approach, for example:
(Translated by ChatGPT)
firas-assaad commentedon May 31, 2023
In that case the explicitly set fields are not optional unless they're nil-able, or do you meant that it's technically complex to implement?
Anyway it's just an idea if you want to consider a stricter and more consistent type system instead of adding more special keywords. One thing I notice with the language server is that because users (myself included) ask for a lot of orthogonal features, and there is usually one implementer, the annotations start to get more complex and more inconsistencies can arise.
To be clear, I think you're doing a great job managing all this complexity and carefully reviewing suggestions, but I bring up TypeScript because it's a mature language that went through some similar discussions, and the result is a more consistent and strict model that catches many user errors.
I know that I'm probably not thinking of a lot of the other use cases where my idea won't work. Having any kind of @exact annotation would still be extremely helpful. (I prefer
---@class Student <exact>in your example, assuming there will be new kinds of 'attributes' added to classes in the future)sumneko commentedon May 31, 2023
I can try adding an option that is enabled by default to enable this feature. If many users give feedback that they don't like this feature, I can downgrade it to default disable and provide new annotations to manually mark it.
(Translated by ChatGPT)
firas-assaad commentedon May 31, 2023
That's a good compromise. I assume it'll still be in a new major version (4?) because I know this will break most of my existing code 😅
You can also make a separate pinned issue to announce this change and solicit more user feedback before doing it, like you did for some features in the past. That way more users will see it coming, at least.
firas-assaad commentedon May 31, 2023
It's also worth mentioning that TypeScript provides a
Partial<className>syntax for cases where you want to opt-out of exact types and tell the compiler that all the fields are optional:42 remaining items
lewis6991 commentedon Aug 22, 2023
You're right. That one isn't so straight forward, but
selfis usually an instance. It doesn't necessarily point tom, though it technically could.LuaLS would need to run a static analysis, so it shouldn't matter where the assignment happens, just that it does.
lewis6991 commentedon Aug 22, 2023
My approach doesn't treat
selfas part of the class definition.firas-assaad commentedon Aug 22, 2023
Right. I misread it. So how would you handle say
self.w = 3inside the init function?lewis6991 commentedon Aug 22, 2023
Warning.
selfshould be treated as an instance.See #1990 (comment)
support `---@Class (exact)`
firas-assaad commentedon Aug 25, 2023
@sumneko Thank you so much for implementing this. It already helped me spot some issues in my code.
Is it possible to emit a warning when a table is defined here (when setting
w = 2):Also for nested cases:
Let me know if you prefer that I open another issue for this.
Edit: the issue is probably the same as this one: #2288
lewis6991 commentedon Aug 25, 2023
Am I right in guessing that in c2018e0 methods never report a warning?
bavalpey commentedon Jun 27, 2024
Is there a reason this is still open considering we have
(exact)?mikavilpas commentedon Jun 27, 2024
@bavalpey I think this should be open. The following should report an error but doesn't
MillhioreBT commentedon Jun 27, 2024
In these cases it works, however in the case of
---@typeit seems not. It's weird but it makes sense that it would work, or maybe not? I hope some expert on the subject has something to say.make lua-classes exact.
WTFox commentedon Sep 15, 2025
Sorry if I missed this somewhere, but is this still planned to be addressed? Is there a workaround anyone has found in the meantime?
sumneko commentedon Sep 15, 2025
Here is a workaround for now
WTFox commentedon Sep 15, 2025
Great, thanks!
feat!: describe constructors and enum variants in generated script de…