Skip to content

Instantly share code, notes, and snippets.

@flatlinediver
Last active February 8, 2021 02:06
Show Gist options
  • Save flatlinediver/d900f27a64626836e8d334a0314b54c5 to your computer and use it in GitHub Desktop.
Save flatlinediver/d900f27a64626836e8d334a0314b54c5 to your computer and use it in GitHub Desktop.
Constructing Styled Theme with inferred units
type ItemsWithUnit<T> = T & { [P in keyof T & string as `_${P}`]: T[P] };
const withUnit = <T>(items: T, unit = 'px'): ItemsWithUnit<T> => {
let newObj = {};
Object.keys(items).forEach((key) => {
const originalElement = items[key as keyof T];
if (typeof originalElement !== 'number') {
newObj = {
...newObj,
[key]: originalElement,
};
return;
}
newObj = {
...newObj,
[`_${key}`]: originalElement,
get [key]() {
return `${originalElement}${unit || 'px'}`;
},
};
});
return newObj as ItemsWithUnit<T>;
};
// Usage
const breakpoints = withUnit({
xs: 0,
sm: 600,
md: 960,
lg: 1280,
xl: 1920,
});
// output
{
xs: '0px',
sm: '600px',
md: '960px',
lg: '1280px',
xl: '1920px',
_xs: 0,
_sm: 600,
_md: 960,
_lg: 1280,
_xl: 1920,
};
// We get to use breakpoints.sm with pixels included, but also use the number value directly to compute something else
// If we also couple it with inferring the theme type, we get all types for free ( intellisense included )
import {} from 'styled-components';
import { CSSProp } from 'styled-components';
declare module 'styled-components' {
type Theme = typeof theme;
export interface DefaultTheme extends Theme {}
}
declare module 'react' {
interface Attributes {
css?: CSSProp<DefaultTheme> | CSSObject;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment