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

  • 相关阅读:
    python学习第三 天-字典
    购物车
    python学习第二天-字符串
    python学习第二天-元组
    git 工作流中的 Sourcetree 和命令行操作对比
    服务端推送通信技术及其优劣势
    关于立即调用的函数表达式(IIFE)
    序列化和反序列化
    mac 使用 brew 安装 nginx 及各种命令
    前端安全问题之CSRF和XSS
  • 原文地址:https://www.cnblogs.com/Answer1215/p/14769583.html
Copyright © 2011-2022 走看看