I'm following the example in the docs for creating media templates, and I'm really struggling to type the arguments to pass to the css function (plain JS version from example):
const sizes = {
desktop: 992
}
const media = Object.keys(sizes).reduce((acc, label) => {
acc[label] = (...args) => css` // <----- how to type args
@media(max-width: ${sizes[label]}px) {
${css(...args)}
}
`
return acc
}, {})
In case you know TS but not styled-components, args is a tagged template literal, so I would use the media object as such:
media.desktop`
background-color: blue;
${variable}
`
I have tried to type args as TemplateStringsArray but TS complains because spread arguments need to be of array type (which I think it is but somehow it is not recognised). If I change the type to TemplateStringsArray[], the css() function complains because it expects at least 1 argument, but received 0 or more.
The signature for a tagged template should be (literals: TemplateStringsArray, ...placeholders: any[]) => string where literals are the strings in the template and placeholders are the variable values.
If you just want to pass all arguments to the css you can use call. Typescript will not let you spread directly because css has required arguments that the ts compiler tries to check for:
acc[label] = (...args: any[]) => css`
@media(max-width: ${sizes[label]}px) {
${css.call(undefined, ...args)}
}
`
A fully typed version that correctly specifies the types for the media.* functions would be :
const sizes = {
desktop: 992
}
const media = Object.keys(sizes).reduce((acc, label) => {
acc[label] = (literals: TemplateStringsArray, ...placeholders: any[]) => css`
@media(max-width: ${sizes[label]}px) {
${css(literals, ...placeholders)}
}
`;
return acc
}, {} as Record<keyof typeof sizes, (l: TemplateStringsArray, ...p: any[]) => string>)
The Titian Cernicova-Dragomir solution is great but doesn't work for me.
It produces a string with commas.
So I add join to css function.
import { css } from "styled-components";
const sizes = {
desktop: 730,
};
const media = Object.keys(sizes).reduce(
(acc, label) => {
acc[label] = (literals: TemplateStringsArray, ...placeholders: any[]) =>
css`
@media (max-width: ${sizes[label]}px) {
${css(literals, ...placeholders)};
}
`.join("");
return acc;
},
{} as Record<
keyof typeof sizes,
(l: TemplateStringsArray, ...p: any[]) => string
>,
);
export default media;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With