網站搜尋

typescript - 在 styled-components 中為 css 函數進行類型定義


我正在按照文檔中的範例創建媒體模板,但我在輸入要傳遞給 css 函數的參數(範例中的純 JS 版本)時遇到了很大的困難:

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
}, {})

如果你知道 TS 但不熟悉 styled-components,args 是一個標記模板字面量,所以我會這樣使用 media 物件:

media.desktop`
  background-color: blue;
  ${variable}
`

我嘗試將 args 的類型指定為 TemplateStringsArray,但 TypeScript 抱怨說展開參數需要是 array 類型(我認為它是,但不知為何沒有被識別)。如果我將類型改為 TemplateStringsArray[],css() 函數又會抱怨,因為它至少需要一個參數,但收到的是 0 個或更多。

答案#1

標記模板的簽名應該是 (literals: TemplateStringsArray, ...placeholders: any[]) => string,其中 literals 是模板中的字串,placeholders 是變數的值。

如果你只是想將所有參數傳遞給 css,你可以使用 call。Typescript 不會讓你直接展開,因為 css 有必需的參數,ts 編譯器會嘗試檢查這些參數:

acc[label] = (...args: any[]) => css`  
  @media(max-width: ${sizes[label]}px) {
    ${css.call(undefined, ...args)}
  }

`

一個完整的類型版本,正確地為 media.* 函數指定類型的版本將是:

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>)

答案#2

Titian Cernicova-Dragomir 的解決方案很好,但對我來說不起作用。它會生成一個帶有逗號的字串。所以我在 css 函數中加入了 join。

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;