• [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

  • 相关阅读:
    jquery2 数据缓存
    gb2312和utf8 转换
    extlangzh_CN.js错误“未结束的字符串常量”
    easyui datagrid 查询
    jQuery获取Select选择的Text和 Value(转)
    JavaScript无提示关闭窗口(兼容IE/Firefox/Chrome)
    简单介绍一些HTML代码(字幕、音频和视频)
    《JavaScript语言精粹》读书笔记
    在本地安装git的HTML帮助文档
    《卓有成效的程序员》读书笔记
  • 原文地址:https://www.cnblogs.com/Answer1215/p/14769583.html
Copyright © 2020-2023  润新知