Skip to content

Conversation

clairep94
Copy link
Collaborator

@clairep94 clairep94 commented Aug 3, 2025

pr05 Typescript Migration 5: Migrate the client/commonfolder

Context:

  1. git mv someComponent.jsx someComponent.tsx. If possible, commit without the no-verify flag, otherwise with no-verify.
  2. Add unit test to secure current behaviour
  3. Check for all instances of useage for the common component to determine props types
  4. Add props types & unit test update
  5. Refactor if beneficial -- did minimal refactoring on this one compared to previous PRs and focused on typescript
  6. Add JSDocs

Changes:

  • .prettierrc -- remove hardcoded parser: "babel" setting
    • This was causing prettier to always use babel even though eslint config has overrides for ts and tsx files
  • RouterTab
  • Button
  • ButtonOrLink
  • IconButton
  • icon
    • was not able to figure out how to migrate this as just updating the file to ts broke the snapshot tests for the generated classes
  • usePrevious
  • useKeyDownHandler
  • onModalClose
  • useSyncFormTranslation

Didn't migrate the storebook files as I wasn't able to run storybook locally to verify against silent regression

Notes:

I have verified that this pull request:

  • has no linting errors (npm run lint)
  • has no test errors (npm run test)
  • is from a uniquely-named feature branch and is up to date with the develop branch.
  • is descriptively named and links to an issue number, i.e. Fixes #123

@clairep94 clairep94 added the pr05 Grant Projects pr05 Grant Projects label Aug 3, 2025
@clairep94 clairep94 marked this pull request as ready for review August 3, 2025 13:04
@clairep94
Copy link
Collaborator Author

@raclim @khanniie Ready for review! Can be reviewed separately from the utils folder migration PR

import styled from 'styled-components';
import { Link } from 'react-router-dom';

import { Link, LinkProps } from 'react-router-dom';
import { remSize, prop } from '../theme';

const kinds = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think this could also be a typescript enum


const displays = {
block: 'block',
inline: 'inline'
} as const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here!

const buttonTypes = {
button: 'button',
submit: 'submit'
} as const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here

display: Display;
};

type SharedButtonProps = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be an interface instead? same for all other similar cases with the Props

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/**
* Specifying an href will use an <a> to link to the URL
*/
href?: string | null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feels like if href can be undefined then we should avoid also letting it be null?

* Allows for IconButton to pass `focusable="false"` as a prop for SVGs.
* See @types/react > interface SVGAttributes<T> extends AriaAttributes, DOMAttributes<T>
*/
focusable?: boolean | 'true' | 'false';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have it just be the boolean type? if the parent that is using this component has the information stored as a string we should have it be the parents' responsibility to cast it to a boolean type before it's passed in

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bump!

@@ -181,69 +249,7 @@ const Button = ({
);
};

Button.defaultProps = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's so great that we can get rid of all of this extra code at the bottom of the React files now haha, thanks for doing this conversion!!

*/
export type ButtonOrLinkProps = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be an interface?

ButtonProps,
'iconBefore' | 'display' | 'focusable'
> & {
icon?: ComponentType<{ 'aria-label'?: string }> | null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here maybe prefer to remove the | null and let the nullish cases all be undefined

* @param value - The current value to track.
* @returns The previous value before the current render, or undefined if none.
*/
export default function usePrevious(value: number): number | undefined {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any way we can avoid having it be typed to numbers specifically? Maybe this is a rare case where it makes sense to use any or unknown? that way the hook can be used for more general cases in the future

@khanniie khanniie requested a review from raclim August 13, 2025 23:43
@clairep94
Copy link
Collaborator Author

Ready for re-review @khanniie @raclim

Copy link
Collaborator

@khanniie khanniie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great!! thanks so much for all the changes!

secondary: 'secondary'
} as const;
enum Kinds {
primary = 'primary',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think enums should use constant case for the fields! https://google.github.io/styleguide/tsguide.html#naming-rules-by-identifier-type

also, i don't think you really need the strings fwiw, there may be a few rare cases where the value itself gets used for some javascript/api logic but if it's used primarily as a categorization method in typescript-only code, i think we can do something like this?

enum Kinds {
   PRIMARY,
   SECONDARY,
}

same thing for the others!

* Allows for IconButton to pass `focusable="false"` as a prop for SVGs.
* See @types/react > interface SVGAttributes<T> extends AriaAttributes, DOMAttributes<T>
*/
focusable?: boolean | 'true' | 'false';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bump!

Button.displays = displays;

export default Button;
Button.kinds = Kinds;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feels like instead of doing this, we could just export Kinds and Displays? like

export enum Kinds

and then other files can do this:

import {Kinds as ButtonKinds} from Button

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr05 Grant Projects pr05 Grant Projects
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants