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包管理命令 dpkg、apt和aptitude
    Linux curses库使用
    VC皮肤库SkinSharp 1.0.6.6的使用
    HOG(方向梯度直方图)
    2014年国外发布的中国内地大学排名18强名单
    sql语句中BEGIN TRAN...COMMIT TRAN
    搜索框中“请输入搜索keyword”
    IOS基于新浪微博开放平台微博APP
    php字符串标点等字符截取不乱吗 封装方法
    谈一谈struts2和springmvc的拦截器
  • 原文地址:https://www.cnblogs.com/Answer1215/p/14769583.html
Copyright © 2011-2022 走看看