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

  • 相关阅读:
    ACM题目————食物链
    ACM题目————Find them, Catch them
    hdu 1255 覆盖的面积 (线段树处理面积覆盖问题(模板))
    poj 3373 Changing Digits (DFS + 记忆化剪枝+鸽巢原理思想)
    hdu 3303 Harmony Forever (线段树 + 抽屉原理)
    hdu 2665 Kth number(划分树模板)
    poj 1348 Computing (四个数的加减乘除四则运算)
    hdu 1021 Fibonacci Again(找规律)
    HDU 1560 DNA sequence (IDA* 迭代加深 搜索)
    hdu 1560 DNA sequence(搜索)
  • 原文地址:https://www.cnblogs.com/Answer1215/p/14769583.html
Copyright © 2011-2022 走看看