Issue
I have a Class with a method that I’d like to use in a de-structured way, mostly due to several optional arguments. I would also like to keep the strict typing so I created an Interface to describe the arguments.
To be clear, this works just fine today, albeit a bit cumbersome, especially if most functions take de-structured arguments.
My question is: Is it possible to define an interface inside the class?
The reason is purely for code readability/maintenance: for larger classes, I have to scroll to outside the class to make changes to a "function" interface, where it would be much clearer to have the interface next to the function
Example of what works:
interface LoadUsersInterface {
status: 'active' | 'inactive',
options?: QueryOptions
}
class UserService {
loadUsers({ status, options }: LoadUsersInterface) {
...
}
}
Example of what I would like:
class UserService {
interface LoadUsersInterface {
status: 'active' | 'inactive',
options?: QueryOptions
}
loadUsers({ status, options }: LoadUsersInterface) {
...
}
}
Note: This is being done within an Angular 11 app, in case there’s any magic there that I don’t know about, although I think this is more of a JS / TypeScript question.
Solution
No, it is not currently possible to declare types or interfaces directly inside of a class
body. See microsoft/TypeScript#7061 for the relevant feature request, and specifically there is this comment which mentions the particular use case of declaring types so they are next to the methods that use them. It is a relatively old issue, and while it is technically open, it is labeled "Revisit". While it’s possible something will eventually happen to support this, I wouldn’t count on it. You may wish to go there and give it a 👍 or describe your use case if you think it’s more compelling than what’s there, but I doubt it will make much of a difference either way.
For now there are only workarounds. If you need a named type, you should probably just declare it outside the class the way you are currently doing and deal with the inconvenience of scrolling.
If you don’t need a name because you only use it once, you can use an anonymous type directly where you would normally refer to the name:
class UserService {
loadUsers({ status, options }: {
status: 'active' | 'inactive',
options?: QueryOptions
}) {
// impl
}
}
But this might not be as clean as you’d like. Oh well!