是否可以从非文字数组派生并集?

我试过这个:

const tokens = {
  "--prefix-apple": "apple",
  "--prefix-orange": "orange"
};

const tokenNames = Object.keys(tokens).map(token => token.replace("--prefix-", ""));

type TokenNamesWithoutPrefix = typeof tokenNames[number] 

但是,当我想要"apple" | "orange"时,它返回类型string

推荐答案

您需要能够在类型级别执行此操作,因为您在这里使用的内置函数只返回string个类型.因此,您需要处理字符串文字类型的泛型类型.

让我们从这个开始:

type StripPrefix<T extends string, Prefix extends string> =
  T extends `${Prefix}${infer Result}`
    ? Result
    : T

type Test = StripPrefix<'--prefix-foo-bar', '--prefix-'>
//   ^? 'foo-bar'

这是一种类型,它判断字符串文字类型是否以前缀开头,然后推断该前缀后面的字符串文字类型.

如果未找到匹配项,则类型将原封不动地解析为T.


现在,我们需要一个函数来执行此操作并强制执行这些类型.

function removePrefix<
  T extends string,
  Prefix extends string
>(token: T, prefix: Prefix): StripPrefix<T, Prefix> {
  return token.replace(prefix, "") as StripPrefix<T, Prefix>
}

在这里,要开始的令牌被捕获为类型T,而要修剪的前缀被捕获为类型Prefix.

但我们需要在返回值为as的情况下进行类型断言.这是因为字符串上的replace方法总是只返回类型string.因此,如果你知道进入的类型,我们可以执行更好的类型,这是我们新的StripPrefix类型.


另一个问题是,Object.keys总是返回string[],而从不返回特定的键.这是因为实际对象可能具有比类型所知的更多的键.

const obj1 = { a: 123, b: 456 }
const obj2: { a: number } = obj1 // fine
const keys = Object.keys(obj2) // ['a', 'b']

在该代码片段中,obj2有两个键,但该类型只知道一个键.

因此,如果您确定这种情况不会发生,或者您确定它发生了也不重要,那么您可以使用另一个类型断言来强类型键数组:

const myObjectKeys = Object.keys(tokens) as (keyof typeof tokens)[]

然后将其映射到前面的函数上,它应该会像您预期的那样工作.

const tokenNames = tokenKeys.map(token => removePrefix(token, "--prefix-"));
//    ^? ('apple' | 'orange')[]

See Typescript playground

Typescript相关问答推荐

如何在不使用变量的情况下静态判断运算式的类型?

如何根据数据类型动态注入组件?

类型{...}的TypeScript参数不能赋给类型为never的参数''

TypeScript Page Routing在单击时不呈现子页面(React Router v6)

Angular 错误NG0303在Angular 项目中使用app.Component.html中的NGFor

无法正确推断嵌套泛型?

如何在TypeScrip中正确键入元素和事件目标?

如何判断对象是否有重叠的叶子并产生有用的错误消息

TS如何不立即将表达式转换为完全不可变?

Angular:ngx-echart 5.2.2与Angular 9集成错误:NG 8002:无法绑定到选项,因为它不是div的已知属性'

按函数名的类型安全类型脚本方法包装帮助器

TypeScrip:使用Union ToInterval辅助对象,但保留子表达式

如何使这种一对一关系在旧表上起作用?

基于未定义属性的条件属性

Angular NG8001错误.组件只能在一个页面上工作,而不是在她的页面上工作

如何静态键入返回数组1到n的函数

任何导航器都未处理有效负载为";params";:{";roomId";:";...";}}的导航操作

可以将JS文件放在tsconfig';s includes/files属性?或者,我如何让tsc判断TS项目中的JS文件?

如何在TypeScript中将元组与泛型一起使用?

记录的子类型<;字符串,X>;没有索引签名