假设我有这个 JavaScript 对象:
const myObject = {
id: 'my_id', // Base value that following value's structures will be depended on (always pascal case).
upperID: 'MY_ID', // Uppercase of `id`.
camelID: 'myId', // Camel case of `id`.
}
我想使用 TypeScript 来确保 id
始终是 pascal 小写。 upperID
和 camelID
具有与上述不同的字符串结构的相同“值”。在 TypeScript 中声明此 myObject
类型的最佳方式是什么?
最佳答案
使用提供的 Uppercase<T>
大写字母非常容易实用程序类型。
type CasedIds<ID extends string> = {
id: ID,
upperID: Uppercase<ID>
}
const myObject: CasedIds<'my_id'> = {
id: 'my_id',
upperID: 'MY_ID',
} as const
Camel 案例变得棘手。因此,首先您需要一个可以对字符串执行此操作的类型。
可能有几种方法可以做到这一点。这是一个。
type CamelCase<T extends string> =
T extends `${infer Pre}_${infer Letter}${infer Post}`
? `${Pre}${Capitalize<Letter>}${CamelCase<Post>}`
: T
type TestCamel = CamelCase<'abc_def_ghi'> // 'abcDefGhi'
让我们来看看这个。
这个泛型以字符串类型作为泛型参数T
.然后检查是否 T
扩展包含下划线后跟一些字符的特定模式的字符串。
如果是,则从该模式中推断出一些子字符串。推断下划线前的部分为Pre
, 下划线后的字符为 Letter
字符串的其余部分为 Post
.否则,只需按原样使用字符串类型即可。
然后我们可以从 Pre
中创建一个新字符串Letter
大写,Post
.但可能还有更多下划线,所以我们在 Post
上再次执行整个操作.这是一种递归类型,当没有下划线时停止递归。
剩下的就很简单了:
type CamelCase<T extends string> =
T extends `${infer Pre}_${infer Letter}${infer Post}`
? `${Pre}${Capitalize<Letter>}${CamelCase<Post>}`
: T
type CasedIds<ID extends string> = {
id: ID,
upperID: Uppercase<ID>
camelID: CamelCase<ID>
}
const myObject: CasedIds<'my_id'> = {
id: 'my_id',
upperID: 'MY_ID',
camelID: 'myId',
} as const
尽管您可能需要一个函数为您构建这些:
function makeId<T extends string>(id: T): CasedIds<T> {
return {} as unknown as CasedIds<T> // mock a real implementation
}
const myId = makeId('my_id')
myId.id // type: 'my_id'
myId.upperID // type: 'MY_ID'
myId.camelID // type: 'myId'
关于javascript - 使用 Typescript 声明字符串结构的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74382893/