Несколько объявлений ключей для перечислений в Typescript

#typescript #enums

#typescript #перечисления

Вопрос:

Я добавляю текстовый компонент в Typescript, который может иметь несколько разных типов: <Text type='h2'>Hello World</Text> .

Я использую объект styles, который имеет эти типы в качестве ключей, чтобы я мог извлекать из них правильные стили. Этот тип должен быть только одной из нескольких возможностей.

 import React from 'react'
import { colors } from '../../config'

const getKeyValue = <U extends keyof T, T extends object>(key: U) => (obj: T) => obj[key]

const styles = {
  h1: {
    fontSize: "46px",
    lineHeight: "64px",
    fontWeight: 300,
  },
  h2: {
    fontSize: "34px",
    lineHeight: "48px",
    fontWeight: 300,
  },
  h3: {
    fontSize: "28px",
    lineHeight: "40px",
    fontWeight: 400,
  },
  h4: {
    fontSize: "23px",
    lineHeight: "32px",
    fontWeight: 400,
  },
  h5: {
    fontSize: "16px",
    lineHeight: "32px",
    fontWeight: 600,
  },
  h6: {
    fontSize: "13px",
    lineHeight: "24px",
    fontWeight: 600,
  },
  h7: {
    fontSize: "11px",
    lineHeight: "16px",
    fontWeight: 600,
  },
  subtitle1: {
    fontSize: "16px",
    lineHeight: "24px",
    fontWeight: 600,
  },
  subtitle2: {
    fontSize: "12px",
    lineHeight: "16px",
    fontWeight: 600,
  },
  body1: {
    fontSize: "16px",
    lineHeight: "24px",
    fontWeight: 400,
  },
  body2: {
    fontSize: "13px",
    lineHeight: "24px",
    fontWeight: 400,
  },
  button: {
    fontSize: "13px",
    lineHeight: "24px",
    fontWeight: 600,
  },
  caption: {
    fontSize: "11px",
    lineHeight: "16px",
    fontWeight: 400,
  }
}

interface Style {
  fontSize: string;
  lineHeight: string;
  fontWeight: number;
}

interface Styles {
  h1: Style; h2: Style; h3: Style; h4: Style; h5: Style; h6: Style; h7: Style;
  subtitle1: Style; subtitle2: Style; body1: Style; body2: Style; button: Style; caption: Style;
}

interface Props {
  children: string;
  type: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'h7' | 'subtitle1' | 'subtitle2' | 'body1' | 'body2' | 'button' | 'caption';
  color?: string;
  ellipsis?: boolean;
  fontWeight?: any;
  onChange?: any;
}

const Text = ({ children, type, color = colors.darkGrey, ellipsis = false, fontWeight }: Props) => {

  const style = {
    ...getKeyValue<keyof Styles, Styles>(type)(styles),
    color,
    minHeight: 25, // TODO: remove this arbitrary height
    textOverflow: ellipsis ? 'ellipsis' : 'none',
    overflow: ellipsis ? 'hidden' : 'none',
    whiteSpace: ellipsis ? 'nowrap' : 'none',
  } as React.CSSProperties

  if (typeof fontWeight !== 'undefined') {
    style.fontWeight = fontWeight
  }

  return <div style={style} >{children}</div>
}

export default Text


  

Это все хорошо, но я объявляю ключи объекта styles три раза:

  • В самом объекте styles
  • В интерфейсе стилей
  • В объявлении типа type

Это кажется излишним, но я слишком новичок в Typescript, чтобы знать, как я могу сделать лучше.

Можно ли это сделать более кратким / лучшим способом, и если да, то как?

Ответ №1:

Вы можете определить Styles и type в отношении предполагаемого типа styles константы. Чтобы получить тип константы, которую мы можем использовать typeof , и получить ключи того типа, который мы можем использовать keyof . Затем мы можем использовать Record для создания Styles типа (запись — это тип с заданным набором ключей одного и того же типа)

 
type StyleType = keyof typeof styles
type Styles = Record<StyleType, Style>
  

Ссылка на игровую площадку