您需要能够在类型级别执行此操作,因为您在这里使用的内置函数只返回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个