Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

types: improve the types returned by styled #32

Merged
merged 3 commits into from
Feb 5, 2025

Conversation

RJWadley
Copy link
Contributor

@RJWadley RJWadley commented Feb 2, 2025

improvements, in no particular order:

  • style props are filtered from the component props
    if we were to use a style prop that already existed on the component, our type would not reflect it
const Sample= styled('div', ({ onClick }: { onClick: string }) => ({
  color: onClick,
}))

in this example, previously onClick was MouseEventHandler<HTMLDivElement> & string, but because style props are filtered, a more correct type is just string

  • style props are not allowed to break the component type
    because style props are filtered, if a required component prop and a style prop share a name we now get a type error
const component = ({
  className,
  color,
}: {
  className: string
  color: number
}) => <div className={className}>{color}</div>

// @ts-expect-error extending with color would make color always undefined, but color must be a number
const extended = styled(component, ({ color }: { color: string }) => ({
  color,
}))
  • extra properties are not allowed
    previously, if style props was a function our component props were expanded to Record<string, unknown> which would let us add incorrect props
const Extended = styled(
  Extended2,
  ({ color }: { color: string }) => ({
    color,
  })
)

const test= (
  <Extended
    className="abc"
    // @ts-expect-error name does not exist on type, but previously was allowed anyway
    name="abc"
  />
)
  • generic types are preserved
    this also adds support for generic type propagation, so if we style a generic function component the generic will be preserved. do note that generic class components will not be propagated, only generic function components.
const Component = <SomeText extends string>({
  id,
  className,
}: {
  id: `id-${SomeText}`
  className?: string
}) => <div></div>
const Extended = styled(Component, { color: 'red' })

const example= (
  <>
    <Component<'abc'> id="id-abc" />
    {/* our generic is preserved! previously was a type error */}
    <Extended<'abc'> id="id-abc" color="red" />
  </>
)

Copy link

vercel bot commented Feb 2, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
restyle ✅ Ready (Inspect) Visit Preview 💬 Add feedback Feb 3, 2025 5:33pm

@RJWadley
Copy link
Contributor Author

RJWadley commented Feb 3, 2025

test is failing due to some issue related to corepack and the npm registry

I could find some workaround right now but I'd rather just wait for that to settle a bit

EDIT: all good now

Copy link
Owner

@souporserious souporserious left a comment

Choose a reason for hiding this comment

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

Thank you so much for fixing these types up and adding tests 🙏 just a question about the package manager change, but otherwise this looks great!

@@ -6,4 +6,4 @@
dist
node_modules
out

tsconfig.vitest-temp.json
Copy link
Owner

Choose a reason for hiding this comment

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

I haven't seen this before, does this get added from --typecheck?

Copy link
Contributor Author

@RJWadley RJWadley Feb 5, 2025

Choose a reason for hiding this comment

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

yeah, it's a temporary file that only exists while tests are running. as soon as the tests are finished it will be deleted.
I've added it here mainly so it doesn't show up in git commands or the vscode ui

"vitest-browser-react": "^0.0.4"
},
"engines": {
"node": ">=20.0.0"
},
"packageManager": "[email protected]"
"packageManager": "[email protected]+sha512.c89847b0667ddab50396bbbd008a2a43cf3b581efd59cf5d9aa8923ea1fb4b8106c041d540d08acb095037594d73ebc51e1ec89ee40c88b30b8a66c0fae0ac1b",
Copy link
Owner

Choose a reason for hiding this comment

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

Is there a reason we need to pin to a sha?

Copy link
Contributor Author

@RJWadley RJWadley Feb 5, 2025

Choose a reason for hiding this comment

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

it works either way. corepack adds it by default because it makes installation less prone to supply chain attacks if e.g. a registry server was compromised. on the other hand, it's a bit annoying to have a massive hash in the package file.

if you prefer without lmk and I'll rebase it out of existence (or you can)

Copy link
Owner

Choose a reason for hiding this comment

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

Ah, didn't realize corepack did that by default, makes sense! Yeah, I can update it and keep a simple version for now.

@souporserious souporserious merged commit 0cef68a into souporserious:main Feb 5, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants