Change `styled()` types so that it works with libraries like Framer Motion
Describe the enhancement
When extending custom components, Linaria's types require that component to have the style prop [link] (kudos for setting that requirement in the type system - really helpful and solid 💪).
This works with usual custom components, but fails to work with e.g. Framer Motion. I believe this is a result of 2 things:
- Linaria requiring the
stylesprop to beCSSProperties[link] (which is fair), - Framer Motion's
styleprop to be an extension ofCSSPropertiesallowing for passing motion values tostyles[link].
Granted, the problem lies probably more on the FM's extension of styles, but I figured it'd be easier for Linaria to relax the styles type requirement, considering that (if I understand correctly) the only purpose that Linaria requires styles is for is setting the custom properties. So the type could be relaxed to a mere Record<string, unknown> maybe?
Motivation
Framer Motion is a great animation library with an api allowing for fantastic components composition/extension with the api that Linaria (and similar css-in-js libs) provide. Would be great if Linaria's types worked with it seamlessly, just like e.g. Styled Components' types do.
So the type could be relaxed to a mere Record<string, unknown> maybe?
It actually seems to be working - I used patch-package to apply this patch to @linaria/[email protected]:
diff --git a/node_modules/@linaria/react/types/styled.d.ts b/node_modules/@linaria/react/types/styled.d.ts
index c790c46..f6fa008 100644
--- a/node_modules/@linaria/react/types/styled.d.ts
+++ b/node_modules/@linaria/react/types/styled.d.ts
@@ -11,9 +11,9 @@ type Has<T, TObj> = [T] extends [TObj] ? T : T & TObj;
export declare const omit: <T extends Record<string, unknown>, TKeys extends keyof T>(obj: T, keys: TKeys[]) => Omit<T, TKeys>;
declare function styled(componentWithStyle: () => any): (error: 'The target component should have a className prop') => void;
declare function styled<TProps extends Has<TMustHave, {
- style?: React.CSSProperties;
+ style?: Record<string, unknown>;
}>, TMustHave extends {
- style?: React.CSSProperties;
+ style?: Record<string, unknown>;
}, TConstructor extends Component<TProps>>(componentWithStyle: TConstructor & Component<TProps>): ComponentStyledTagWithInterpolation<TProps, TConstructor>;
declare function styled<TProps extends Has<TMustHave, {
className?: string;
and the problem is gone, while the style prop on Linaria components remains type-safe. I'll keep monitoring for the issue while writing more code / corner cases.
Hi,
I had a similar requirement. React's type declarations suggest extending the parent interface of CSS.Properties. If that doesn't work (as in my case) you can try augmenting react's CSS.Properties directly:
import * as CSS from "csstype";
declare global {
namespace React {
interface CSSProperties extends CSS.Properties<string | number> {
[index: string]: unknown;
}
}
}
This has to be included by your tsconfig.json before restarting the TS language server.
It seems you found a solution using patch-package @jalooc ?