adobe / react-spectrum

A collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.
https://react-spectrum.adobe.com
Apache License 2.0
13.1k stars 1.14k forks source link

Updating typescript surfaces type errors in starter kit #7434

Open steveoh opened 3 days ago

steveoh commented 3 days ago

Provide a general summary of the issue here

Updating the packages in the tailwind starter kit after downloading the ab9fd5c68 build has typescript errors.

๐Ÿค” Expected Behavior?

The types should be good regardless of the typescript version used

๐Ÿ˜ฏ Current Behavior

Running tsc on the default codebase throw errors in 4 components.

src/Checkbox.tsx:59:9 - error TS2322: Type '{ children: (Element | ReactNode | ((values: CheckboxRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]; }' is not assignable to type '{ children?: ReactNode; }'.
  Types of property 'children' are incompatible.
    Type '(Element | ReactNode | ((values: CheckboxRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]' is not assignable to type 'ReactNode'.
      Type '(Element | ReactNode | ((values: CheckboxRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]' is not assignable to type 'Iterable<ReactNode>'.
        The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
          Type 'IteratorResult<Element | ReactNode | ((values: CheckboxRenderProps & { defaultChildren: ReactNode; }) => ReactNode), undefined>' is not assignable to type 'IteratorResult<ReactNode, any>'.
            Type 'IteratorYieldResult<Element | ReactNode | ((values: CheckboxRenderProps & { defaultChildren: ReactNode; }) => ReactNode)>' is not assignable to type 'IteratorResult<ReactNode, any>'.
              Type 'IteratorYieldResult<Element | ReactNode | ((values: CheckboxRenderProps & { defaultChildren: ReactNode; }) => ReactNode)>' is not assignable to type 'IteratorYieldResult<ReactNode>'.
                Type 'Element | ReactNode | ((values: CheckboxRenderProps & { defaultChildren: ReactNode; }) => ReactNode)' is not assignable to type 'ReactNode'.
                  Type '(values: CheckboxRenderProps & { defaultChildren: ReactNode; }) => ReactNode' is not assignable to type 'ReactNode'.

59         <>
           ~~

src/GridList.tsx:42:9 - error TS2322: Type '{ children: (Element | ReactNode | ((values: GridListItemRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]; }' is not assignable to type '{ children?: ReactNode; }'.
  Types of property 'children' are incompatible.
    Type '(Element | ReactNode | ((values: GridListItemRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]' is not assignable to type 'ReactNode'.
      Type '(Element | ReactNode | ((values: GridListItemRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]' is not assignable to type 'Iterable<ReactNode>'.
        The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
          Type 'IteratorResult<Element | ReactNode | ((values: GridListItemRenderProps & { defaultChildren: ReactNode; }) => ReactNode), undefined>' is not assignable to type 'IteratorResult<ReactNode, any>'.
            Type 'IteratorYieldResult<Element | ReactNode | ((values: GridListItemRenderProps & { defaultChildren: ReactNode; }) => ReactNode)>' is not assignable to type 'IteratorResult<ReactNode, any>'.
              Type 'IteratorYieldResult<Element | ReactNode | ((values: GridListItemRenderProps & { defaultChildren: ReactNode; }) => ReactNode)>' is not assignable to type 'IteratorYieldResult<ReactNode>'.
                Type 'Element | ReactNode | ((values: GridListItemRenderProps & { defaultChildren: ReactNode; }) => ReactNode)' is not assignable to type 'ReactNode'.
                  Type '(values: GridListItemRenderProps & { defaultChildren: ReactNode; }) => ReactNode' is not assignable to type 'ReactNode'.

42         <>
           ~~

src/RadioGroup.tsx:48:23 - error TS2322: Type '{ children: (Element | ReactNode | ((values: RadioRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]; }' is not assignable to type '{ children?: ReactNode; }'.
  Types of property 'children' are incompatible.
    Type '(Element | ReactNode | ((values: RadioRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]' is not assignable to type 'ReactNode'.
      Type '(Element | ReactNode | ((values: RadioRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]' is not assignable to type 'Iterable<ReactNode>'.
        The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
          Type 'IteratorResult<Element | ReactNode | ((values: RadioRenderProps & { defaultChildren: ReactNode; }) => ReactNode), undefined>' is not assignable to type 'IteratorResult<ReactNode, any>'.
            Type 'IteratorYieldResult<Element | ReactNode | ((values: RadioRenderProps & { defaultChildren: ReactNode; }) => ReactNode)>' is not assignable to type 'IteratorResult<ReactNode, any>'.
              Type 'IteratorYieldResult<Element | ReactNode | ((values: RadioRenderProps & { defaultChildren: ReactNode; }) => ReactNode)>' is not assignable to type 'IteratorYieldResult<ReactNode>'.
                Type 'Element | ReactNode | ((values: RadioRenderProps & { defaultChildren: ReactNode; }) => ReactNode)' is not assignable to type 'ReactNode'.
                  Type '(values: RadioRenderProps & { defaultChildren: ReactNode; }) => ReactNode' is not assignable to type 'ReactNode'.

48       {renderProps => <>
                         ~~

src/TagGroup.tsx:110:9 - error TS2322: Type '{ children: (Element | ReactNode | ((values: TagRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]; }' is not assignable to type '{ children?: ReactNode; }'.
  Types of property 'children' are incompatible.
    Type '(Element | ReactNode | ((values: TagRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]' is not assignable to type 'ReactNode'.
      Type '(Element | ReactNode | ((values: TagRenderProps & { defaultChildren: ReactNode; }) => ReactNode))[]' is not assignable to type 'Iterable<ReactNode>'.
        The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
          Type 'IteratorResult<Element | ReactNode | ((values: TagRenderProps & { defaultChildren: ReactNode; }) => ReactNode), undefined>' is not assignable to type 'IteratorResult<ReactNode, any>'.
            Type 'IteratorYieldResult<Element | ReactNode | ((values: TagRenderProps & { defaultChildren: ReactNode; }) => ReactNode)>' is not assignable to type 'IteratorResult<ReactNode, any>'.
              Type 'IteratorYieldResult<Element | ReactNode | ((values: TagRenderProps & { defaultChildren: ReactNode; }) => ReactNode)>' is not assignable to type 'IteratorYieldResult<ReactNode>'.
                Type 'Element | ReactNode | ((values: TagRenderProps & { defaultChildren: ReactNode; }) => ReactNode)' is not assignable to type 'ReactNode'.
                  Type '(values: TagRenderProps & { defaultChildren: ReactNode; }) => ReactNode' is not assignable to type 'ReactNode'.

110         <>
            ~~

Errors  Files
     1  src/Checkbox.tsx:59
     1  src/GridList.tsx:42
     1  src/RadioGroup.tsx:48
     1  src/TagGroup.tsx:110

๐Ÿ’ Possible Solution

I'm not quite sure. The error seems off to me. I could use a second set of eyes on the error.

๐Ÿ”ฆ Context

{
  "devDependencies": {
    "@babel/preset-react": "^7.25.9",
    "@storybook/addon-essentials": "^8.4.5",
    "@storybook/addon-interactions": "^8.4.5",
    "@storybook/addon-links": "^8.4.5",
    "@storybook/addon-onboarding": "^8.4.5",
    "@storybook/blocks": "^8.4.5",
    "@storybook/react": "^8.4.5",
    "@storybook/react-vite": "^8.4.5",
    "@storybook/testing-library": "^0.2.2",
    "@types/react": "^18.3.12",
    "@types/react-dom": "^18.3.1",
    "autoprefixer": "^10.4.20",
    "prop-types": "^15.8.1",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "storybook": "^8.4.5",
    "tailwindcss-react-aria-components": "^1.2.0",
    "typescript": "5.7.2",
    "vite": "^5.4.11"
  },
  "scripts": {
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build",
    "check": "tsc"
  },
  "dependencies": {
    "lucide-react": "^0.461.0",
    "postcss": "^8.4.49",
    "react-aria-components": "latest",
    "tailwind-variants": "^0.3.0",
    "tailwindcss": "^3.4.15",
    "tailwindcss-animate": "^1.0.7"
  },
  "resolutions": {
    "@types/mime": "3.0.4",
    "jackspeak": "2.1.1"
  }
}

๐Ÿ–ฅ๏ธ Steps to Reproduce

  1. Download the starter kit.
  2. Extract and cd into the directory.
  3. run npx npm-check-updates -i --format group,repo and install every dependency. If there is a lock conflict, run rm -rf node_modules package-lock.json && npm install && npm audit fix and repeat until there are no newer packages or conflicts
  4. Add an npm script called check that runs tsc
  5. run npm run check

Version

1.5.0

What browsers are you seeing the problem on?

Firefox, Chrome, Safari, Microsoft Edge

If other, please specify.

No response

What operating system are you using?

macos

๐Ÿงข Your Company/Team

No response

๐Ÿ•ท Tracking Issue

No response

JonnyDawe commented 3 days ago

I've hit the same issue when updating my project to the latest typescript release. I reverted to version 5.6.3 and no longer see the error.

writes-of-spring commented 1 day ago

I can't figure out why it's only coming to light with ts 5.7, but I believe it has to do with the type of children (GridListItemProps, CheckboxProps, RadioProps, because the 4 components can take children as a function whereas the tailwind starter assumes these render props are used in the reusable component and just returns a ReactNode as a child.

so either check if the child is a function and pass the arguments, as below, or augment the props and only allow ReactNode

 <AriaCheckbox
      {...props}
      ref={ref}
      className={composeRenderProps(props.className, (className, renderProps) =>
        checkboxStyles({
          ...renderProps,
          isInvalid: props.isInvalid,
          className,
        }),
      )}
    >
      {({ isSelected, isIndeterminate, ...renderProps }) => (
        <>
          <div
            className={boxStyles({
              isSelected: isSelected || isIndeterminate,
              ...renderProps,
            })}
          >
            {isIndeterminate ? (
              <Minus aria-hidden className={iconStyles} />
            ) : isSelected ? (
              <Check aria-hidden className={iconStyles} />
            ) : null}
          </div>
          {typeof props.children === "function"
            ? props.children({ isSelected, isIndeterminate, ...renderProps })
            : props.children}
        </>
      )}
    </AriaCheckbox>

OR

export const Checkbox = React.forwardRef(function Checkbox(
  props: Omit<CheckboxProps, "children"> & { children?: ReactNode },
  ref: React.Ref<HTMLLabelElement>,
)...