Type [...] is missing the following properties from type Pick<ButtonHTMLAttributes,[...]: css, sx TS2739
See original GitHub issueDescribe the bug When consuming this component:
type Props = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "className">;
const Button = React.forwardRef<HTMLButtonElement, Props>((props) => {
return <button {...props} />
});
resulting in type (as reported by VS Code on hover & by inspecting the compiled d.ts):
const Button: React.ForwardRefExoticComponent<
Pick<
ButtonHTMLAttributes<HTMLButtonElement>,
| "autoFocus"
| "disabled"
| "form"
| "formAction"
| "formEncType"
| "formMethod"
| ... 259 more ...
| "sx"
> &
React.RefAttributes<...>
>;
from another Theme UI-agnostic project it encounters the following type error:
Type ‘{ children: string; }’ is missing the following properties from type ‘Pick<ButtonHTMLAttributes<HTMLButtonElement>, “autoFocus” | “disabled” | “form” | “formAction” | “formEncType” | “formMethod” | “formNoValidate” | … 258 more … | “sx”>’: css, sx TS2739
To Reproduce
- Clone https://github.com/yuriybelike/repro__theme-ui__css_sx_props
- On components-library, run
npm i
- On consumer, run
npm i
- On consumer – in order to see the TypeScript error – either:
- open “src/App.tsx” on VS Code
- run
npm run start
Expected behavior
Consumer isn’t affected by Theme UI related types on primitive JSX elements like <button>
Additional context
- I was unable to reproduce the issue when removing
Omit<>
orforwardRef()
- I understand this is partially TypeScript’s issue, as it converts
Omit<>
intoPick<>
- I’ve used
tsdx
for the library scaffolding, but I don’t think it is related, as my original project is usingcreate-react-library
- On my original project the issue was still reproducible on TypeScript v3.8.3
Workaround
You can just omit both props like
type Props = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "className" | "css" | "sx">;
but I find it far from ideal having to account for Theme UI specific props on such a primitive type as it is ButtonHTMLAttributes
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (4 by maintainers)
Top GitHub Comments
@hasparus the more docs, the better, in my opinion. Feel free to add stuff as you go, even if it’s WIP or something we don’t link to
I would be nice if TypeScript recognized
sx
andcss
prop only ifjsx
imported from Theme UI is set in the pragma comment for current file.Unfortunately, JSX support in TypeScript isn’t perfect. It doesn’t work like this, and both Theme UI and Emotion inject its pragma supported prop into all React components.
Problem
I reproduced the problem.
Omit
is compiled toPick
. (Why? 😮)theme-ui
is not a dependency ofconsumer
, we don’t havesx
prop (from Theme UI) norcss
prop (from Emotion) types in it.Pick<ButtonHTMLAttributes<HTMLButtonElement>, 'sx'>
isunknown
.sx
was optional, but we don’t know it inconsumer
.I have two workarounds for you.
Workaround 1
Add
theme-ui
as peer dependency.Theme UI with its 20.3kB gzipped (okay, it’s treeshakable but still) may be too big to use as a hidden dependency. Due to component libraries hiding their dep on styling libraries, big applications often end up with multiple styling libs in the bundle (I once had styled-components, emotion and goober).
Since Theme UI uses React context for theming, the theme for your component library can be overriden by your user. I find it nice to be frank about it and advertise it as a feature instead of a surprising bug.
Both React context and JSX types make Theme UI hard to hide.
Workaround 2
Make sure
Props
are not inlined withinterface
keyword.Type aliases can be inlined during the build.
We can use
interface
keyword and export our props. This is generally a good idea. They’re public anyway and they can be accessed withReact.ComponentProps<typeof Button>
, but exportingButtonProps
for convenience is quite nice IMO.I’d prefer
interface
for library public API, because it introduces a named type (which won’t get inlined), allows declaration merging, and error messages with them are more succint and thus less scary.https://www.typescriptlang.org/docs/handbook/advanced-types.html#interfaces-vs-type-aliases