我有反对意见:

const themes = {
  light: {
    a...
    b...
  },
  dark: {
    a...
    b...
    c...
    d...
  },

React组件从上面的对象中获取了一个colorsprops ,它是作为主题之一提供的,它在不同的主题中包含内部key: value个条目的不同集合. 例如,在我的组件中,我访问colors.d,但TS辩称,无论我试图给他什么类型,都是错误的.

我做了什么try :

  1. 完全不起作用,TS说是Property 'd' does not exist on type { a, b, ... }
export type TThemes = typeof themes['light'] | typeof themes['dark'] | (...some more of them)

But when i export only one 100, which i use exactly in react-component - it works, but i need to take care of all themes.

  1. 试过了,TS说只有Property 'd' does not exist on type 'TThemes' :
{ [K in keyof typeof themes]: typeof themes[K] }

那么,当主题内部可能不同,但类型需要像[{...}, {...}, ...](which TS again doesn't like)一样时,我应该做些什么才能让colors.d正常工作?

UPD:主题代码的有效版本:

const themes = {
    bordered: {
        background: COLORS.BgMain,
        borderWidth: '1px',
        radius: '4px',
        padding: '20px',
        mobilePadding: '15px',
        color: COLORS.TextPrimary
    },
    simple: {
        background: 'transparent',
        borderWidth: '1px 0',
        radius: '0px',
        padding: '20px 0',
        mobilePadding: '15px 0',
        color: COLORS.TextPrimary
    },
    light: {
        border: COLORS.BgLight,
        background: COLORS.BgLight,
        color: COLORS.TextPrimary,
        colorArrow: COLORS.GRAY_DARK,
        backgroundIcon: COLORS.BgSecondary,
        borderIcon: COLORS.BgSecondary,
        colorArrowIsOpen: COLORS.GRAY_DARK,
        backgroundIconIsOpen: COLORS.Outline_Light,
        borderIconIsOpen: COLORS.Outline_Light,
        radius: BorderRadius.componentRadius,
        padding: '20px 24px',
        mobilePadding: '15px',
        storyColor: COLORS.BgMain,
    },
    dark: {
        border: COLORS.Control,
        background: COLORS.Control,
        color: COLORS.TextWhite,
        colorArrow: COLORS.Control,
        backgroundIcon: COLORS.GRAY_DARK,
        borderIcon: COLORS.GRAY_DARK,
        colorArrowIsOpen: COLORS.Control,
        backgroundIconIsOpen: COLORS.TextWhite,
        borderIconIsOpen: COLORS.TextWhite,
        radius: BorderRadius.componentRadius,
        padding: '20px 24px',
        mobilePadding: '15px',
        storyColor: '#3D3D3D',
    },
};

推荐答案

我认为您想要所有子对象的属性的并集.(如果我错了,请纠正我).

首先,通过追加as const使主题对象保持不变:

const themes = {
  ...
} as const;

然后,您可以获得所有属性的交集(窄):

type CommonObjectNarrow = typeof themes["bordered"] | typeof themes["simple"] | typeof themes["dark"] | typeof themes["light"];
type CommonPropsNarrow = keyof CommonObjectNarrow; 
// "background" | "radius" | "padding" | "mobilePadding" | "color"

或所有属性的并集(宽):

type ThemeKeys = keyof typeof themes;
type Props<K extends ThemeKeys> = (keyof typeof themes[K]);
type CommonPropsWide = Props<"bordered"> | Props<"simple"> | Props<"dark"> | Props<"light">;
// "background" | "borderWidth" | "radius" | "padding" | "mobilePadding" | "color" 
// | "border" | "colorArrow" | "backgroundIcon" | "borderIcon" | "colorArrowIsOpen" 
// | "backgroundIconIsOpen" | "borderIconIsOpen" | "storyColor"
type CommonObjectWide = {
  [k in CommonPropsWide]: string;
}

以下是typescript playground人中可以证实这一点的东西:

declare const COLORS:{ [x:string]: string};
declare const BorderRadius: { componentRadius: string};

const themes = {
    bordered: {
        background: COLORS.BgMain,
        borderWidth: '1px',
        radius: '4px',
        padding: '20px',
        mobilePadding: '15px',
        color: COLORS.TextPrimary
    },
    simple: {
        background: 'transparent',
        borderWidth: '1px 0',
        radius: '0px',
        padding: '20px 0',
        mobilePadding: '15px 0',
        color: COLORS.TextPrimary
    },
    light: {
        border: COLORS.BgLight,
        background: COLORS.BgLight,
        color: COLORS.TextPrimary,
        colorArrow: COLORS.GRAY_DARK,
        backgroundIcon: COLORS.BgSecondary,
        borderIcon: COLORS.BgSecondary,
        colorArrowIsOpen: COLORS.GRAY_DARK,
        backgroundIconIsOpen: COLORS.Outline_Light,
        borderIconIsOpen: COLORS.Outline_Light,
        radius: BorderRadius.componentRadius,
        padding: '20px 24px',
        mobilePadding: '15px',
        storyColor: COLORS.BgMain,
    },
    dark: {
        border: COLORS.Control,
        background: COLORS.Control,
        color: COLORS.TextWhite,
        colorArrow: COLORS.Control,
        backgroundIcon: COLORS.GRAY_DARK,
        borderIcon: COLORS.GRAY_DARK,
        colorArrowIsOpen: COLORS.Control,
        backgroundIconIsOpen: COLORS.TextWhite,
        borderIconIsOpen: COLORS.TextWhite,
        radius: BorderRadius.componentRadius,
        padding: '20px 24px',
        mobilePadding: '15px',
        storyColor: '#3D3D3D',
    },
};


type CommonObjectNarrow = typeof themes["bordered"] | typeof themes["simple"] | typeof themes["dark"] | typeof themes["light"];
type CommonPropsNarrow = keyof CommonObjectNarrow; // "background" | "radius" | "padding" | "mobilePadding" | "color"


type ThemeKeys = keyof typeof themes;
type Props<K extends ThemeKeys> = (keyof typeof themes[K]);
type CommonPropsWide = Props<"bordered"> | Props<"simple"> | Props<"dark"> | Props<"light">;
// "background" | "borderWidth" | "radius" | "padding" | "mobilePadding" | "color" 
// | "border" | "colorArrow" | "backgroundIcon" | "borderIcon" | "colorArrowIsOpen" 
// | "backgroundIconIsOpen" | "borderIconIsOpen" | "storyColor"
type CommonObjectWide = {
  [k in CommonPropsWide]: string;
}

更新

在回应OP的 comments 时:

declare enum COLORS { 
    TextPrimary = "#1",
    BgMain = "#1",
    BgLight = "#2",
    GRAY_DARK = "#3",
    BgSecondary = "#4",
    Outline_Light = "#5",
    Control = "#6",
    TextWhite = "#7"
};
declare const BorderRadius: { componentRadius: "5pix 0"};

const themes = {
    bordered: {
        background: COLORS.BgMain,
        borderWidth: '1px',
        radius: '4px',
        padding: '20px',
        mobilePadding: '15px',
        color: COLORS.TextPrimary
    },
    simple: {
        background: 'transparent',
        borderWidth: '1px 0',
        radius: '0px',
        padding: '20px 0',
        mobilePadding: '15px 0',
        color: COLORS.TextPrimary
    },
    light: {
        border: COLORS.BgLight,
        background: COLORS.BgLight,
        color: COLORS.TextPrimary,
        colorArrow: COLORS.GRAY_DARK,
        backgroundIcon: COLORS.BgSecondary,
        borderIcon: COLORS.BgSecondary,
        colorArrowIsOpen: COLORS.GRAY_DARK,
        backgroundIconIsOpen: COLORS.Outline_Light,
        borderIconIsOpen: COLORS.Outline_Light,
        radius: BorderRadius.componentRadius,
        padding: '20px 24px',
        mobilePadding: '15px',
        storyColor: COLORS.BgMain,
    },
    dark: {
        border: COLORS.Control,
        background: COLORS.Control,
        color: COLORS.TextWhite,
        colorArrow: COLORS.Control,
        backgroundIcon: COLORS.GRAY_DARK,
        borderIcon: COLORS.GRAY_DARK,
        colorArrowIsOpen: COLORS.Control,
        backgroundIconIsOpen: COLORS.TextWhite,
        borderIconIsOpen: COLORS.TextWhite,
        radius: BorderRadius.componentRadius,
        padding: '20px 24px',
        mobilePadding: '15px',
        storyColor: '#3D3D3D',
    },
};

type ThemeKeys = keyof typeof themes;
type Theme<K extends ThemeKeys> = typeof themes[K];
type Props<K extends ThemeKeys> = (keyof typeof themes[K]);
type CommonPropsWide = Props<"bordered"> | Props<"simple"> | Props<"dark"> | Props<"light">;

type KeyTypes1<k extends string, themeKeys extends ThemeKeys[] = ["bordered","simple","dark","light"], t extends any = never> = 
  themeKeys extends [infer HEAD, ... infer TAIL] ?  
  TAIL extends ThemeKeys[] ?
  HEAD extends ThemeKeys ?
  (k extends keyof Theme<HEAD> ? KeyTypes1<k,TAIL,Theme<HEAD>[k] | t> : KeyTypes1<k,TAIL,t>)
    : never : never : t;

type CommonObjectWide = Partial<{
  [k in CommonPropsWide]: KeyTypes1<k>
}>

const obj1: CommonObjectWide = {
    color: COLORS.BgSecondary,
    background: "", //COLORS.BgMain
    radius: BorderRadius.componentRadius, // ""
}

const obj2: CommonObjectWide = {
    color: "", // COLORS.BgSecondary,  error, must be color
    background: COLORS.BgMain,
    radius: "5pix 0"
}

显示为TypeScript PLayground.

Typescript相关问答推荐

使用FormArray在Angular中添加排序

TypScript手册中的never[]参数类型是什么意思?

如何修复正在处理类型但与函数一起使用时不处理的类型脚本类型

如何根据另一个属性的布尔值来缩小函数属性的返回类型?

Redux—Toolkit查询仅在不为空的情况下添加参数

contextPaneTitleText类型的参数不能分配给remoteconfig类型的关键参数'""'''

键集分页顺序/时间戳上的筛选器,精度不相同

当方法参数和返回类型不相互扩展时如何从类型脚本中的子类推断类型

如何在另一个参数类型中获取一个参数字段的类型?

为什么在leetcode问题的测试用例中,即使我确实得到了比预期更好的解决方案,这段代码也失败了?

(TypeScript)TypeError:无法读取未定义的属性(正在读取映射)"

有没有办法防止类型交集绕过联合类型限制?

在正常函数内部调用异步函数

创建一个TypeScrip对象并基于来自输入对象的约束定义其类型

如何使用TypeScrip在EXPO路由链路组件中使用动态路由?

基于闭包类型缩小泛型类型脚本函数的范围

TypeScript中的这些条件类型映射方法之间有什么区别?

显式推断对象为只读

React HashRouter,单击导航栏时页面重新加载出现问题

如何确定单元格中的块对 mat-h​​eader-cell 的粘附(粘性)?