Skip to content

Instantly share code, notes, and snippets.

@pbedat
Created March 27, 2018 05:31
Show Gist options
  • Select an option

  • Save pbedat/26eb9376ac11041e1106cad5f1e7606f to your computer and use it in GitHub Desktop.

Select an option

Save pbedat/26eb9376ac11041e1106cad5f1e7606f to your computer and use it in GitHub Desktop.
react-jss typescript
declare module 'react-jss' {
import * as React from 'react';
export interface CSSProperties extends React.CSSProperties {
composes?: string | string[]
}
export type StyleSheet<Props = {}>
= Record<
string,
CSSProperties
| ((props: Props) => React.CSSProperties)
>;
type StyleRules<ClassKey extends string = string, Props = {}>
= Record<ClassKey, CSSProperties
| ((props: Props) => React.CSSProperties)>;
export type ClassNameMap<ClassKey extends string = string> = Record<ClassKey, string>;
export interface WithStyles<ClassKey extends string = string> {
classes: ClassNameMap<ClassKey>
}
export interface StyledComponentProps<ClassKey extends string = string> {
classes?: Partial<ClassNameMap<ClassKey>>
}
function injectSheet<ClassKey extends string>(
style: StyleRules<ClassKey>,
options?: any,
): <P>(
component: React.ComponentType<P & WithStyles<ClassKey>>,
) => React.ComponentType<P & StyledComponentProps<ClassKey>>;
export default injectSheet;
export const jss: any
export const JssProvider: any
}
const styles: StyleSheet<Props> = { // you don't have to type `styles` explicitly, but it helps you with code completion
root: {
color: "red",
composes: ["btn", "btn-default"]
},
header: ({important}) => ({
fontWeight: important ? 'bold' : 'normal'
}),
"&:hover": {
color: "blue",
"& a": {
textDecoration: 'none'
} as React.CSSProperties
}
}
interface Props {
important: boolean
}
const Comp = injectSheet(styles)<Props>(({ classes, important }) => (
<div className={classes.root}>
<h1 className={classes.header}>Hello JSS</h1>
</div>
))
type StyledProps = WithStyles<keyof typeof styles> & Props;
const ClassComp = injectSheet(styles)(class extends React.Component<StyledProps> {
render() {
const {classes} = this.props;
return (
<div className={classes.root}>
<h1 className={classes.header}>Hello JSS</h1>
</div>
)
}
})
@tylermassey
Copy link

Thanks for providing this. With those typings, did TS complain about your nested CSS? I had to modify StyleSheet like so

type StyleSheet<Props = {}> = Record<
    string,
    | CSSProperties
    | ((props: Props) => React.CSSProperties)
    | Record<string, CSSProperties>
  >;

@janhartmann
Copy link

janhartmann commented Sep 6, 2018

I am trying to do something like:

const styles: StyleSheet<ISidebarProps> = (theme: ITheme) => ({
  root: {
    background: theme.colors.background
  }
});

Anyone know how to modify the types so the theme can be passed in?

Type '(theme: ITheme) => { root: { background: string; }; }' is not assignable to type 'Record<string, CSSProperties | Record<string, CSSProperties> | ((props: ISidebarProps) => CSSProperties)>'.
  Index signature is missing in type '(theme: ITheme) => { root: { background: string; }; }'.

@Saturate
Copy link

Saturate commented Sep 10, 2018

@janhartmann I did a quick an dirty fix:

export type StyleSheetThemed<Props = Function>
    = (theme: any) => StyleSheet;

@pbedat
Copy link
Author

pbedat commented Dec 17, 2018

FYI the @types/react-jss typings seem to have matured by now. Use them instead of this snippet =)

@Saturate
Copy link

Saturate commented Dec 17, 2018

Just tried to verify it, it does not work with dynamic values:

https://github.com/cssinjs/jss/tree/master/packages/react-jss#dynamic-values

Sample code:

import * as React from 'react';
import injectSheet from 'react-jss';

interface IStyles {
	root: string;
	rootDynamic: string;
}

const styles = theme => ({
	root: {
		padding: 20,
		color: theme.colors.primary,
		[theme.breakpoints.up('sm')]: {
			padding: 10
		}
	},
	rootDynamic: (props: IPrintNameProps) => ({
		fontSize: props.size
	})
});

export interface IPrintNameProps {
	name: string;
	size: number;
	classes: IStyles;
	style?: React.CSSProperties;
}

class PrintName extends React.Component<IPrintNameProps> {
	public render() {
		return (
			<div className={this.props.classes.root}>
				test
			</div>
		);
	}
}

export default injectSheet(styles)(PrintName);

Oh and if I don't define classes prop, the I the following [ts] Property 'classes' does not exist on type 'Readonly<{ children?: ReactNode; }> & Readonly<IPrintNameProps>'.

So something is wrong here, it should inject those props. I'm on [email protected] btw.

@JasonKaz
Copy link

JasonKaz commented Jan 1, 2019

Can confirm with Saturate, this one and the definitions in @types/react-jss do not support dynamic values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment