Tìm kiếm trang web

typescript - Kiểu hóa hàm css trong styled-components


Tôi đang theo ví dụ trong tài liệu để tạo các mẫu phương tiện, và tôi thực sự gặp khó khăn khi gõ các đối số để truyền vào hàm css (phiên bản JS thuần từ ví dụ):

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

Trong trường hợp bạn biết TS nhưng không biết styled-components, args là một tagged template literal, vì vậy tôi sẽ sử dụng đối tượng media như sau:

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

Tôi đã cố gắng gõ args dưới dạng TemplateStringsArray nhưng TS báo lỗi vì các đối số trải cần phải thuộc kiểu array (mà tôi nghĩ là đúng nhưng bằng cách nào đó nó lại không được nhận diện). Nếu tôi thay đổi kiểu thành TemplateStringsArray[], hàm css() lại báo lỗi vì nó yêu cầu ít nhất 1 đối số, nhưng nhận được 0 hoặc nhiều hơn.

Câu trả lời #1

Chữ ký cho một template được gắn thẻ nên là (literals: TemplateStringsArray, ...placeholders: any[]) => string trong đó literals là các chuỗi trong template và placeholders là các giá trị biến.

Nếu bạn chỉ muốn truyền tất cả các đối số vào css, bạn có thể sử dụng call. Typescript sẽ không cho phép bạn trải trực tiếp bởi vì css có các đối số bắt buộc mà trình biên dịch ts cố gắng kiểm tra:

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

`

Một phiên bản hoàn chỉnh với kiểu được xác định chính xác cho các hàm media.* sẽ là:

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

Câu trả lời số 2

Giải pháp Titian Cernicova-Dragomir rất tuyệt nhưng không hoạt động với tôi. Nó tạo ra một chuỗi có dấu phẩy. Vì vậy tôi thêm join vào hàm css.

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;