[Typescript] Dynamic types: Use TypeScript's Mapped Types and Template Literal Types Together
we're going to dive deep into a more complex example in which we combine mapped types, key remapping, template literal types, and indexed access types to statically type a highly dynamic JavaScript function in TypeScript.
Start with following code:
function createGetterObject(obj: any): any { const newObj: any = {}; for (const key of Object.keys(obj)) { const cpK = key[0].toUpperCase() + key.substr(1); const getterKey = `get${cpK}`; newObj[getterKey] = () => obj[key]; } return newObj; } const user = createGetterObject({ name: "Wan", twitter: "zhentiw" }) console.log(user) console.log(user.getName()) console.log(user.getTwitter())
We want to get better typings support.
function createGetterObject<T>(obj: T): PropGetters<T> { const newObj: any = {}; for (const key of Object.keys(obj)) { const cpK = key[0].toUpperCase() + key.substr(1); const getterKey = `get${cpK}`; newObj[getterKey] = () => obj[key]; } return newObj; } type PropGetters<T> = { }
Get an error:
This is because `T` can be any as well. We need to limit T type by telling that `T` can be only for Object:
function createGetterObject<T extends Record<string, any>>(obj: T): PropGetters<T> {
In `PropGetter`, we want to create similar to
type PropGetters<T> = { getName: () => sting getTwitter: () => string }
How to make those?
We can start from:
type PropGetters<T> = { [Key in keyof T]: () => T[Key] }
keyof T: get all the keys of T, so we got `name` & `twitter`
T[Key]: as lookup type, `name` prop result in string `Wan`.
This is what we get as a result:
`name` & `twitter` are functions type which return string, not really what we want.
Template Literal Types
type PropGetters<T> = { [Key in keyof T as `get${Key}`]: () => T[Key] }
Got error:
This is because Key can be string, number, boolean... , what we want is just string type, so we can do:
type PropGetters<T> = { [Key in string & keyof T as `get${Key}`]: () => T[Key] }
Now, we got:
We actual want `getName` not as `getname`, to fix this, we can do:
type PropGetters<T> = { [Key in string & keyof T as `get${Capitalize<Key>}`]: () => T[Key] }
Now the type should works. If we add another prop `id`:
Typescript can tell the return value is a number type.
Final piece to limit `T` in `PropGetters`:
type PropGetters<T extends Record<string, any>> = { [Key in string & keyof T as `get${Capitalize<Key>}`]: () => T[Key] }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2020-05-14 [Mise] Focus in input field on page load with `x-init` in Alpine JS
2020-05-14 [Mise] Focus an input field on button click with `x-ref` and the `$refs` property in Alpine JS
2020-05-14 [Mise] Keep a DOM input and state value in sync with the `x-model` directive in Alpine JS
2020-05-14 [Mise] Control enter and leave transitions with the `x-show.transition` modifier in Alpine JS
2020-05-14 [Mise] Iterate through data with the `x-for` attribute in Alpine JS
2020-05-14 [Mise] Toggle visibility and styles based on state with `x-show` and `x-bind` in Alpine JS
2020-05-14 [Mise] Update a count state value with the x-on event listener directive in Alpine JS