簡體   English   中英

使用道具在樣式化組件中有條件地設置屬性以使用 TypeScript 在主題對象上建立索引?

[英]Conditionally set attributes in styled-component using props to index on theme object with TypeScript?

概述

我有一個使用styled-components ThemeProvidernext.js (react) TypeScript 項目。 我正在嘗試對theme對象進行索引,該對象將基於rem的字體大小存儲為strings並按點大小( integer )進行索引。 我遇到的問題是我無法根據從組件傳遞的 prop 動態設置索引。 錯誤消息、代碼示例、嘗試的解決方案和觀察結果如下

錯誤信息

Element implicitly has an 'any' type because expression of type 'number' can't be used to index type '{ 14: string; 12: string; 10: string; }'.

  No index signature with a parameter of type 'number' was found on type '{ 14: string; 12: string; 10: string; }'.


代碼示例

主題對象類型定義

樣式.d.ts

import "styled-components";

declare module "styled-components" {

  export interface DefaultTheme {
    fonts: {
      size: {
        14: string;
        12: string;
        10: string;
      };
    }
  }
}


樣式組件theme對象

主題.ts

import { DefaultTheme } from "styled-components";

const theme: DefaultTheme = {
  fonts: {
    size: {
      14: "0.875rem",
      12: "0.75rem",
      10: "0.625rem"
    },
  }
};

export { theme };


樣式組件

組件.ts

import styled from "styled-components";

const StyledThingie = styled('div')`
  /* 
     HERE IS WHERE THIS ISSUE IS 
     I want to conditionally inject the prop (if fontSize is passed) 
     into the size index to get the rem-based size, and set a default 
     font-size if no prop is passed.

     props.theme.fonts.size[10] works just fine.
  */
  font-size: ${props => (props.fontSize ? props.theme.fonts.size[props.fontSize] : props.theme.fonts.size[10])};
`;

export {
  StyledThingie
}


反應功能組件

Thingie.tsx

import React from "react";
import styled from "styled-components";
import { StyledThingie } from "./components.ts";

const Thingie = styled(StyledThingie)`
  display: block;
`;

const ThingieComponent: React.FC<any> = (props) => {
  return(
    <Thingie fontSize={14}> // HERE IS WHERE I"M PASSING THE PROP
      <p>This paragraph should be set to 0.875rem or theme.fonts.size[14] </p>
    </Thingie>
  );
}


嘗試的解決方案

我試圖根據一些TypeScript 文檔定義index signature ,但不清楚如何實現這一點。 這是我的嘗試:

interface FontSize {
    [index: string]: number;
}

export type StyledThingieProps = {
    fontSize?: FontSize;
}

const StyledThingie = styled('div')<StyledThingieProps>`
  size: ${props => (props.fontSize ? props.theme.fonts.size[props.fontSize] : props.theme.fonts.size[10])};
`;


觀察

我的腦袋疼 ... ;)

當您使用變量索引具有非動態屬性的類型時會導致該錯誤。 因此,要繞過它,您需要更改DefaultTheme.fonts.size的類型聲明以定義動態屬性。 (基本上,類型檢查器無法知道傳遞給索引 ( [] ) 的變量是否與聲明的鍵之一完全匹配。因此您必須說“我可以使用任何數字或字符串鍵” .)

如果您仍想聲明已知鍵:

  export interface DefaultTheme {
    fonts: {
      size: {
        [key: number]: string;
        14: string;
        12: string;
        10: string;
      };
    }

但是,如果你不關心具體的字體大小是什么,你可以這樣做

  export interface DefaultTheme {
    fonts: {
      size: {
        [key: number]: string;
      };
    }

這兩個選項修復了類型定義以接受任何數字作為鍵。 或者,您可以將fontSize強制轉換為鍵類型(使用keyof ),它基本上是一個enum ,其中包含對象的所有鍵作為值。 你告訴類型檢查器“這個變量應該是這些特定值中的任何一個(特定類型中的任何鍵)”:

// in the template where you use the font size
props.theme.fonts.size[props.fontSize as keyof typeof props.theme.fonts.size]
// or using the type declaration directly
props.theme.fonts.size[props.fontSize as keyof DefaultTheme["font"]["size"]]

通過聲明字體大小的類型,您也走上了正確的軌道,但是語法有點錯誤:

export type StyledThingieProps = {
    fontSize?: keyof DefaultTheme["font"]["size"];
}

這是修復它的另一種方法。

我通過以下方式解決了它:

export const TextInput = styled.TextInput.attrs(({theme}) => ({ placeholderTextColor: theme.colors.primary, }))
font-family: ${({ theme }) =`enter code here`> theme.fonts.interBold};
font-size: 18px;
color: ${({ theme }) => theme.colors.primary};
;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM