在 TypeScript 中将字符串映射到模板字面量类型
在 TypeScript 中,有没有一种方法可以将字符串映射到匹配的模板字面量类型?
这是一个例子:
type SomeType<T> = {
[P in keyof T as `as${Capitalize<string & P>}`]: number;
};
这应当获取 T 的每一个属性 x 并将其变为一个属性 asX。
但现在我想把一个属性名称例如 foo 转换为 asFoo,并且让 TypeScript 可以检测到。
我希望能够做到这一点:
interface I {
foo: number;
bar: number;
}
const obj: SomeType<I> = {
asFoo: 1,
asBar: 2,
};
const str = 'foo';
// Doesn't work, trying to capitalize str, but TypeScript only sees it as a string
obj[`as${str[0].toUpperCase()}${str.slice(1)}`];
我想以某种方式使用 str 来索引 obj。这有可能吗?我想我可以将字符串进行类型转换,但我宁愿不这样做。
目前我通过创建像这样的函数来处理这个问题:
function getProperty(key: string): keyof SomeType<I> {
return key === 'foo' ? 'asFoo' : 'asBar';
}
obj[getProperty('foo')];
但我只是想看看是否有更优雅的解决方案,因为如果属性很多,这可能会失控。我对 TypeScript 还比较陌生,所以可能会漏掉一些东西。
答案#1
我通常尝试把我的逻辑拆分成尽可能小的部分。考虑这个例子:
type SomeType<T> = {
[P in keyof T as `as${Capitalize<string & P>}`]: number;
};
interface Obj {
foo: number;
bar: number;
}
const obj: SomeType<Obj> = {
asFoo: 1,
asBar: 2,
};
const capitalize = <Key extends string>(key: Key) =>
`${key[0].toUpperCase()}${key.slice(1)}` as Capitalize<Key>
const withPrefix = <Key extends string>(key: Key): `as${Key}` => `as${key}`
const getProperty = <Key extends string>(key: Key) => withPrefix(capitalize(key))
const result = getProperty('foo') // asFoo
const getter = obj[result] // number
操场
这行 as$ {Capitalize<string & P>} 包含两个操作:
大写化,
添加
as前缀
这就是我为什么为它使用了两个函数
正如你可能注意到的,withPrefix 和 getProperty 可能会被组合:
import { compose } from 'redux'
const capitalize = <Key extends string>(key: Key) =>
`${key[0].toUpperCase()}${key.slice(1)}` as Capitalize<Key>
const withPrefix = <Key extends string>(key: Key): `as${Key}` => `as${key}`
type Fn =
<Key extends string>(key: Key) => `as${Capitalize<Key>}`
const getProperty =
compose(withPrefix, capitalize) as Fn
const result = getProperty('foo') // asFoo
但它要求你使用带有类型断言的额外 compose 函数。
你可以从文档中了解更多关于模板字面量字符串的信息
