Proptypes cleanups#23223
Conversation
The default <Flex> creates the expected layout.
| return a.localeCompare(b); | ||
| }); | ||
| const restarts = daemons.map(service => cockpit.spawn(["systemctl", "restart", service], { superuser: "required", err: "message" })); | ||
| const restarts = daemons.map(service => cockpit.spawn(["systemctl", "restart", service], { superuser: "require", err: "message" })); |
There was a problem hiding this comment.
Ouch! But anything truthy other than "try" is effectively treated as "require", right?
There was a problem hiding this comment.
Yes, I believe so. But I can't find the relevant code in the bridge
| activeTab, | ||
| tabErrors | ||
| }: { | ||
| onChange: (tab: string) => void; |
| return ( | ||
| <Nav variant="horizontal-subnav" id="services-filter" | ||
| onSelect={(_event, result) => { setActiveItem(result.itemId); onChange(result.itemId) }}> | ||
| onSelect={(_event, result) => { setActiveItem(result.itemId as TabKey); onChange(String(result.itemId)) }}> |
There was a problem hiding this comment.
As usual, I am unhappy about the "as" here, but I think short of making Nav generic we have no choice.
| onSelect={(_event, result) => { setActiveItem(result.itemId as TabKey); onChange(String(result.itemId)) }}> | ||
| <NavList> | ||
| {Object.keys(service_tabs).map(key => { | ||
| {(Object.keys(service_tabs) as TabKey[]).map(key => { |
There was a problem hiding this comment.
Unhappy about this "as" as well, but: (I think we can shorting this introduction to "asbut" :-)
I tried to improve this, but it is somewhat involved. The best I could come up with is using a Map instead of a Record. It was a valuable learning experience, so let me share:
If we want proper type inference, we need to use a Map and Map.prototype.keys. Constructing the map is a bit inelegant, and we should move it to the global scope to avoid constructing it all the time:
const service_tabs: Map<TabKey, string> = new Map([
[ "service", _("Services") ],
[ "socket", _("Sockets") ],
[ "target", _("Targets") ],
[ "timer", _("Timers") ],
[ "path", _("Paths") ],
]);
So now we should be able to write service_tabs.keys().map(k => ...) and k should be of type TabKey.
Except that Iterator,prototype.map is only in ES2025 which we probably don't want to depend on just for this. (We would also need to bump our TypeScript version.)
So we could write [...service_tabs.keys()].map(k => ...), but that creates an array at run time. To be fair Object.keys() also creates an array, no?
So we could have another global just to list the keys:
const service_tabs_keys = [...service_tabs.keys()];
and then use service_tabs_keys.map(k => ...).
That would be kinda ok, but is it worth it? I don't know.
There was a problem hiding this comment.
We currently target es2021 in our TypeScript, I had to do some digging and finally found prototype.map which is baseline 2025. So fairly recent and we should target Firefox ESR as minimum which is Firefox 140.
| interface TabRenderer { | ||
| name: string; | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| renderer: React.ComponentType<any>; |
There was a problem hiding this comment.
React.ComponentType<unknown> works as well and doesn't require silencing the error.
There was a problem hiding this comment.
Not, 100%
pkg/shell/credentials.tsx(314,51): error TS2322: Type '({ data: { currentKey: Key; keys?: never; setDialogError?: never; }; name: string; renderer: ({ currentKey }: { currentKey: Key; }) => Element; } | { data: { currentKey: Key; keys: Keys; setDialogError: Dispatch<...>; }; name: string; renderer: ({ currentKey, keys, setDialogError }: { ...; }) => Element; })[]' is not assignable to type 'TabRenderer[]'.
Type '{ data: { currentKey: Key; keys?: never; setDialogError?: never; }; name: string; renderer: ({ currentKey }: { currentKey: Key; }) => Element; } | { data: { currentKey: Key; keys: Keys; setDialogError: Dispatch<...>; }; name: string; renderer: ({ currentKey, keys, setDialogError }: { ...; }) => Element; }' is not assignable to type 'TabRenderer'.
Type '{ data: { currentKey: credentials.Key; keys?: never; setDialogError?: never; }; name: string; renderer: ({ currentKey }: { currentKey: credentials.Key; }) => React.JSX.Element; }' is not assignable to type 'TabRenderer'.
Types of property 'renderer' are incompatible.
Type '({ currentKey }: { currentKey: credentials.Key; }) => React.JSX.Element' is not assignable to type 'ComponentType<unknown>'.
Type '({ currentKey }: { currentKey: credentials.Key; }) => React.JSX.Element' is not assignable to type 'FunctionComponent<unknown>'.
Types of parameters '__0' and 'props' are incompatible.
Type 'unknown' is not assignable to type '{ currentKey: Key; }'.
| } | ||
|
|
||
| interface ListingPanelState { | ||
| activeTab: number; |
There was a problem hiding this comment.
Let's just make this string | number then we can omit the tabIndex = Number(tabIndex) below.
mvollmer
left a comment
There was a problem hiding this comment.
Thanks! I think we should do the changes that I have proposed for ListingPanel.
Assisted-By: Claude Opus 4.6
Assisted-By: Claude Opus
For this to be converted to TypeScript first services.jsx has to be converted which is a non-trivial amount of work. Adding jsdoc is also not trivial due to to the need to define `unit`.
|
RHEL 8 packagekit tests are impossible to get green. |
No description provided.