在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
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 Typestype 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] }
|
请发表评论