2

概述

我有一个next.js(反应)TypeScript 项目正在使用styled-components ThemeProvider. 我正在尝试对存储基于字体大小的theme对象进行索引,并按点大小()进行索引。我遇到的问题是我无法根据从组件传递的道具动态设置索引。错误消息、代码示例、尝试的解决方案和观察结果如下remstringsinteger

错误信息

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
}


反应功能组件

东西.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>
  );
}


尝试的解决方案

我试图index signature根据一些TypeScript docs定义一个,但不清楚如何实现它。这是我尝试的:

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])};
`;


观察

我的脑袋疼 ... ;)

4

2 回答 2

2

当您使用变量来索引具有非动态属性的类型时会导致该错误。因此,要绕过它,您需要更改 的类型声明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"];
}

这是解决它的另一种方法。

于 2020-03-03T21:43:43.027 回答
0

我通过以下方式解决了它:

export const TextInput = styled.TextInput.attrs(({theme}) => ({ placeholderTextColor: theme.colors.primary, }))
font-family: ${({ theme }) => theme.fonts.interBold};
font-size: 18px;
color: ${({ theme }) => theme.colors.primary};
;
于 2021-10-27T18:32:33.557 回答