zoukankan      html  css  js  c++  java
  • [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]
    }

    Read: https://egghead.io/lessons/typescript-use-typescript-s-mapped-types-and-template-literal-types-together

  • 相关阅读:
    Ubuntu 10.04安装google拼音输入法
    Ubuntu 10.04 编译Android 2.1源码
    Android make sdk 错误解决方案
    关于android内核从linux内核分支上除名
    odex打包为可用的apk程序
    取得当前屏幕的截图
    android设备作为视频监控客户端的思路
    政府网站群系统选型
    浅谈网站群的一代与二代技术
    我的2013
  • 原文地址:https://www.cnblogs.com/Answer1215/p/14769583.html
Copyright © 2011-2022 走看看