twin.examples
twin.examples copied to clipboard
Typing component props with Stitches
I've set up twin macros with stitches following the examples but my styled-components export any type.
I was wondering if there's a way to type it so that I can autocomplete the props in VSCode
Here's my twin.d.ts
import "twin.macro";
import { css as cssImport } from "@stitches/react";
import styledImport from "@stitches/react";
// Support a css prop when used with twins styled.div({}) syntax
type CSSProp<T = AnyIfEmpty<DefaultTheme>> = string | CSSObject;
declare module "react" {
// The css prop
interface HTMLAttributes<T> extends DOMAttributes<T> {
css?: CSSProp;
tw?: string;
}
// The inline svg css prop
interface SVGProps<T> extends SVGProps<SVGSVGElement> {
css?: CSSProp;
tw?: string;
}
}
// Support twins styled.div({}) syntax
type StyledTags = {
[Tag in keyof JSX.IntrinsicElements]: CreateStyledComponent<
JSX.IntrinsicElements[Tag]
>;
};
declare module "twin.macro" {
// The styled and css imports
const styled: typeof StyledTags | typeof styledImport;
const css: typeof cssImport;
}
I have a workaround to the issue above by forwarding the ref in order to add props to the exported component:
interface Props {
children?: ReactNode;
size?: "xs" | "sm" | "md" | "lg" | "xl";
}
type Ref = ReactNode | HTMLElement | string;
const StyledButton = styled.button({
...
});
const Button = forwardRef<Ref, Props>(function Button({ ...rest }, ref) {
return <StyledButton ref={ref} {...rest} />;
});
export default Button;
twin.d.ts
import { css as cssImport } from '@stitches/react';
import type * as StyledComponent from '@stitches/react/types/styled-component';
import type * as Util from '@stitches/react/types/util';
import { config, CSS } from '../stitches.config';
import 'twin.macro';
type CSSProp<T = AnyIfEmpty<DefaultTheme>> = CSSObject | string;
type Stitches<Type = string> = <
Composers extends (
| string
| React.ExoticComponent<any>
| React.JSXElementConstructor<any>
| Util.Function
| { [name: string]: unknown }
)[],
>(
...composers: {
[K in keyof Composers]: Composers[K] extends
| string
| React.ExoticComponent<any>
| React.JSXElementConstructor<any>
| Util.Function
? Composers[K]
: CSS & {
variants?: {
[Name in string]: {
[Pair in number | string]: CSS;
};
};
compoundVariants?: (('variants' extends keyof Composers[K]
? {
[Name in keyof Composers[K]['variants']]?:
| Util.Widen<keyof Composers[K]['variants'][Name]>
| Util.String;
} &
Util.WideObject
: Util.WideObject) & {
css: CSS;
})[];
defaultVariants?: 'variants' extends keyof Composers[K]
? {
[Name in keyof Composers[K]['variants']]?:
| Util.Widen<keyof Composers[K]['variants'][Name]>
| Util.String;
}
: Util.WideObject;
} & {
[K2 in keyof Composers[K]]: K2 extends 'compoundVariants' | 'defaultVariants' | 'variants'
? unknown
: K2 extends keyof CSS
? CSS[K2]
: unknown;
};
}
) => StyledComponent.StyledComponent<Type, StyledComponent.StyledComponentProps<Composers>, typeof config.media, CSS>;
type StyledTags = {
[Element in keyof JSX.IntrinsicElements]: Stitches<Element>;
};
declare module 'react' {
interface HTMLAttributes<T> extends DOMAttributes<T> {
css?: CSSProp;
tw?: string;
}
interface SVGProps<T> extends SVGProps<T> {
css?: CSSProp;
tw?: string;
}
}
declare module 'twin.macro' {
const css: typeof cssImport;
const styled: StyledTags;
}
stitches.config.ts
import { createStitches, CSS as StitchesCSS } from '@stitches/react';
const stitches = createStitches({});
export const { css, config, globalCss, keyframes, styled, theme, getCssText } = stitches;
export type CSS = StitchesCSS<typeof stitches>;
This is how I got this "working" in my project.
Few things to note, in the stitches config you need to make sure config and type CSS are exported.
This was tested with v1.0.0-canary.15 of @stitches/react, not v0.2.x.