首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用数组类型索引生成联合类型

使用数组类型索引生成联合类型
EN

Stack Overflow用户
提问于 2021-11-22 10:17:46
回答 3查看 61关注 0票数 2

示例:

代码语言:javascript
复制
type DefaultTheme = {
  name: 'default';
  colors: [string, string, string];
};

type CustomTheme = {
  name: 'custom';
  colors: [string, string, string, string, string];
};

type DefaultColor = ???; // 'default-1' | 'default-2' | 'default-3';

type CustomColor = ???; // 'custom-1' | 'custom-2' | 'custom-3' | 'custom-4' | 'custom-5';

问题是,是否可以使用colors数组的长度来创建映射的联合类型,如给定的示例所示。

为了(希望)清晰起见,简化了这个示例,但是完整地,有一个泛型类型Theme,它使用namelength参数,并使用length生成固定数目的字符串的元组。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-11-22 11:16:41

我简化了@Aleksey L.的解决方案,并采取了不同的方法:

代码语言:javascript
复制
type Indices<T> = keyof T & `${number}`;
type Indices1<T extends [...any]> = Exclude<Indices<[...T, any]>, '0'>

type N_Test = Indices1<[string, string, string]> // '1' | '2' | '3'
type P_Test = `Test-${N_Test}`; // "Test-1" | "Test-2" | "Test-3"

主要不同之处:

  • 不使用即席映射类型{ [key in ...]: ... }
  • 没有递归类型(如@kaja3的答案)。
  • 没有条件类型X extends Y ? ... : ... (Exclude在内部使用这个类型,但它是一个很好的抽象)

应用于该示例:

代码语言:javascript
复制
type DefaultTheme = {
  name: 'default';
  colors: [string, string, string];
};

type CustomTheme = {
  name: 'custom';
  colors: [string, string, string, string, string];
};

type WithPrefix<T extends {name: string, colors: string[]}> = `${T['name']}-${Indices1<T['colors']>}`;

type DefaultColor = WithPrefix<DefaultTheme>; // 'default-1' | 'default-2' | 'default-3';
type CustomColor = WithPrefix<CustomTheme>; // 'custom-1' | 'custom-2' | 'custom-3' | 'custom-4' | 'custom-5';

游乐场

票数 1
EN

Stack Overflow用户

发布于 2021-11-22 11:03:11

下面是邪恶(代码注释中的一些解释):

代码语言:javascript
复制
// Pick only positive number strings
type Positive<N> = N extends `${number}` ? N extends "0" ? never : N : never

// Produce union of possible array indexes (starting from 1)
type IndexFrom1<T extends Array<any>> = keyof { [K in keyof [null, ...T] as Positive<K>]: any }

type WithPrefix<T extends Array<any>, Prefix extends string, Value = IndexFrom1<T>> =
  Value extends string ? `${Prefix}-${Value}` : never

type N_Test = IndexFrom1<[string, string, string]> // "1" | "2" | "3"
type P_Test = WithPrefix<[string, string, string], 'Test'> // "Test-1" | "Test-2" | "Test-3"

现在,将WithPrefix util应用于您的示例:

代码语言:javascript
复制
type DefaultTheme = {
  name: 'default';
  colors: [string, string, string];
};

type CustomTheme = {
  name: 'custom';
  colors: [string, string, string, string, string];
};

type DefaultColor = WithPrefix<DefaultTheme["colors"], DefaultTheme["name"]>; // 'default-1' | 'default-2' | 'default-3';

type CustomColor = WithPrefix<CustomTheme["colors"], CustomTheme["name"]>; // 'custom-1' | 'custom-2' | 'custom-3' | 'custom-4' | 'custom-5';

游乐场

首先,我们使用映射类型生成元组索引的联合。我们将向它再添加一个成员([null, ...T]),然后删除零索引(N extends "0"),从1开始。

接下来,我们使用分布条件类型模板文字类型来生成所需的联合。

代码语言:javascript
复制
Value extends string ? `${Prefix}-${Value}` : never
票数 0
EN

Stack Overflow用户

发布于 2021-11-22 11:10:02

对于一个非邪恶的解决方案,我们可以使用一个助手类型,它将像[string, string, string]这样的元组转换为像1 | 2 | 3这样的联合。这可以使用元组的length属性递归地完成。

代码语言:javascript
复制
type TupleToUnion<T extends any[]> =
    T extends [any, ...infer R] ? T['length'] | TupleToUnion<R> : never

type GenerateUnion<T extends {name: string, colors: string[]}> =
    `${T['name']}-${TupleToUnion<T['colors']>}`

// 'default-3' | 'default-2' | 'default-1'
type DefaultColor = GenerateUnion<DefaultTheme>

// 'custom-5' | 'custom-4' | 'custom-3' | 'custom-2' | 'custom-1'
type CustomColor = GenerateUnion<CustomTheme>

操场连接

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70064173

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档