如何根据对象键派生类型?

问题描述 投票:0回答:1

我需要从 PALETTE 对象派生类型

ColorVariant
。预期结果是:

type ColorVariant = "common.black" | "common.white" | "primary.25" | "primary.50" | "primary.100" | "error.25" | "error.50" | "error.100" | "success.25" | "success.50" | "success.100"

实际结果是:

type ColorVariant = never

代码:

const PALETTE = {
  common: {
    black: "#000",
    white: "#fff",
  },
  primary: {
    25: "#FAFAFF",
    50: "#F5F5FF",
    100: "#E7E7FC",
  },
  error: {
    25: "#FFFBFA",
    50: "#FEF3F2",
    100: "#FEE4E2",
  },
  success: {
    25: "#F6FEF9",
    50: "#ECFDF3",
    100: "#D1FADF",
  },
} as const;

export type Colors = keyof typeof PALETTE;
export type ColorOptions = (typeof PALETTE)[Colors];
export type Tone = keyof ColorOptions;

export type ColorVariant = `${Colors}.${Tone}`;

我确实知道发生这种情况是因为

common
primary, error, success
中的键不同......不幸的是,我不明白如何解决它。请帮忙

这里是TS游乐场

typescript
1个回答
0
投票

您实际上需要迭代

K
中的每个键
keyof Palette
,并为每个这样的键计算 模板文字类型
`${K}.${keyof Palette[K]}`
,然后计算所有这些键的 union。您可以使用 keyof Palette 上的
映射类型
来完成此操作,然后使用 keyof Palette
索引到

这被称为 分布式对象类型 ,在 microsoft/TypeScript#47109 中创造,当你有一个类似键的联合

{[K in KK]: F<K>}[KK]}
和一个类型函数
KK
时,它看起来像
F<>
。它在 F<> 中的联合上
分配
K
类型函数。因此,如果
KK
K1 | K2 | K3
,那么
{[K in KK]: F<K>}[KK]
就是
F<K1> | F<K2> | F<K3>

从概念上来说

ColorVariant
它看起来像

type ColorVariant = { [K in keyof Palette]:
  `${K}.${keyof Palette[K]}` // error!
}[keyof Palette];

但是有一个问题,编译器没有注意到

keyof Pallete[K]
始终可以通过模板文字类型进行序列化。
keyof
运算符可以产生任何
PropertyKey
,即
string | number | symbol
。但只有
string | number
是可序列化的,而
symbol
则不是。因此,您需要根据 Exclude
 的结果 
symbol
 
keyof
来确保编译器可以接受:

type ColorVariant = { [K in keyof Palette]:
  `${K}.${Exclude<keyof Palette[K], symbol>}`
}[keyof Palette];

这就变成了

/* type ColorVariant = "common.black" | "common.white" | 
        "primary.25" | "primary.50" | "primary.100" | 
        "error.25" | "error.50" | "error.100" | 
        "success.25" | "success.50" | "success.100" 
*/

随心所欲。

Playground 代码链接

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.