Create an object type based on properties with same name from multiple objects in Typescript?












2















I'll try to elaborate a bit more because the title is not very clear.



So, I have a few objects of different types where the only things that is the same in all of them is a property which the name (not the type) is the same in all of them. They are all properties of a main object.



I am going to run a reduce to create a new object with properties where the values are the values of those properties with the same name in those objects but the property names are the property names from the main object.



What I need is that the resulting type from this reduce is an object with those props. But I also need this to be a reusable type.



So let's say I have the following object structure:



type SameFoo = {
a: string;
};

type SameBar = {
b: number;
};

type FooType = {
propertyWithSameName: SameFoo;
};

type BarType = {
propertyWithSameName: SameBar;
};

type Main = {
foo: FooType;
bar: BarType;
};

const main: Main = {
foo: { propertyWithSameName: { a: 'something' } },
bar: { propertyWithSameName: { b: 1 } }
};


Now, I'll run a reduce that will transform this into:



const result = {
foo: { a: 'something' },
bar: { b: 1 }
};


The catch here is that I don't know the input types are or the names of the properties, the only thing I know here is the structure and the name of that property with the same name.



// What I know about the structure:
type WhatIKnowAboutTheObject = {
[propName: string]: {
propertyWithSameName: unknown;
[key: string]: unknown;
}
}


But since I want this to be strongly typed, I need to either have the reduce output the object with the correct type or maybe have a type that transforms it, like let's say:



type Result = TransformType<Main>;

// Resulting type:
// type Result = {
// foo: SameFoo;
// bar: SameBar;
// };


So I can do something like:



type Result = TransformType<Main>;
const result: Result = Object.keys(main).reduce(..., {} as Result);


I hope this is clearer, I know this is a very edge use case.



Thanks in advance for the help.










share|improve this question



























    2















    I'll try to elaborate a bit more because the title is not very clear.



    So, I have a few objects of different types where the only things that is the same in all of them is a property which the name (not the type) is the same in all of them. They are all properties of a main object.



    I am going to run a reduce to create a new object with properties where the values are the values of those properties with the same name in those objects but the property names are the property names from the main object.



    What I need is that the resulting type from this reduce is an object with those props. But I also need this to be a reusable type.



    So let's say I have the following object structure:



    type SameFoo = {
    a: string;
    };

    type SameBar = {
    b: number;
    };

    type FooType = {
    propertyWithSameName: SameFoo;
    };

    type BarType = {
    propertyWithSameName: SameBar;
    };

    type Main = {
    foo: FooType;
    bar: BarType;
    };

    const main: Main = {
    foo: { propertyWithSameName: { a: 'something' } },
    bar: { propertyWithSameName: { b: 1 } }
    };


    Now, I'll run a reduce that will transform this into:



    const result = {
    foo: { a: 'something' },
    bar: { b: 1 }
    };


    The catch here is that I don't know the input types are or the names of the properties, the only thing I know here is the structure and the name of that property with the same name.



    // What I know about the structure:
    type WhatIKnowAboutTheObject = {
    [propName: string]: {
    propertyWithSameName: unknown;
    [key: string]: unknown;
    }
    }


    But since I want this to be strongly typed, I need to either have the reduce output the object with the correct type or maybe have a type that transforms it, like let's say:



    type Result = TransformType<Main>;

    // Resulting type:
    // type Result = {
    // foo: SameFoo;
    // bar: SameBar;
    // };


    So I can do something like:



    type Result = TransformType<Main>;
    const result: Result = Object.keys(main).reduce(..., {} as Result);


    I hope this is clearer, I know this is a very edge use case.



    Thanks in advance for the help.










    share|improve this question

























      2












      2








      2








      I'll try to elaborate a bit more because the title is not very clear.



      So, I have a few objects of different types where the only things that is the same in all of them is a property which the name (not the type) is the same in all of them. They are all properties of a main object.



      I am going to run a reduce to create a new object with properties where the values are the values of those properties with the same name in those objects but the property names are the property names from the main object.



      What I need is that the resulting type from this reduce is an object with those props. But I also need this to be a reusable type.



      So let's say I have the following object structure:



      type SameFoo = {
      a: string;
      };

      type SameBar = {
      b: number;
      };

      type FooType = {
      propertyWithSameName: SameFoo;
      };

      type BarType = {
      propertyWithSameName: SameBar;
      };

      type Main = {
      foo: FooType;
      bar: BarType;
      };

      const main: Main = {
      foo: { propertyWithSameName: { a: 'something' } },
      bar: { propertyWithSameName: { b: 1 } }
      };


      Now, I'll run a reduce that will transform this into:



      const result = {
      foo: { a: 'something' },
      bar: { b: 1 }
      };


      The catch here is that I don't know the input types are or the names of the properties, the only thing I know here is the structure and the name of that property with the same name.



      // What I know about the structure:
      type WhatIKnowAboutTheObject = {
      [propName: string]: {
      propertyWithSameName: unknown;
      [key: string]: unknown;
      }
      }


      But since I want this to be strongly typed, I need to either have the reduce output the object with the correct type or maybe have a type that transforms it, like let's say:



      type Result = TransformType<Main>;

      // Resulting type:
      // type Result = {
      // foo: SameFoo;
      // bar: SameBar;
      // };


      So I can do something like:



      type Result = TransformType<Main>;
      const result: Result = Object.keys(main).reduce(..., {} as Result);


      I hope this is clearer, I know this is a very edge use case.



      Thanks in advance for the help.










      share|improve this question














      I'll try to elaborate a bit more because the title is not very clear.



      So, I have a few objects of different types where the only things that is the same in all of them is a property which the name (not the type) is the same in all of them. They are all properties of a main object.



      I am going to run a reduce to create a new object with properties where the values are the values of those properties with the same name in those objects but the property names are the property names from the main object.



      What I need is that the resulting type from this reduce is an object with those props. But I also need this to be a reusable type.



      So let's say I have the following object structure:



      type SameFoo = {
      a: string;
      };

      type SameBar = {
      b: number;
      };

      type FooType = {
      propertyWithSameName: SameFoo;
      };

      type BarType = {
      propertyWithSameName: SameBar;
      };

      type Main = {
      foo: FooType;
      bar: BarType;
      };

      const main: Main = {
      foo: { propertyWithSameName: { a: 'something' } },
      bar: { propertyWithSameName: { b: 1 } }
      };


      Now, I'll run a reduce that will transform this into:



      const result = {
      foo: { a: 'something' },
      bar: { b: 1 }
      };


      The catch here is that I don't know the input types are or the names of the properties, the only thing I know here is the structure and the name of that property with the same name.



      // What I know about the structure:
      type WhatIKnowAboutTheObject = {
      [propName: string]: {
      propertyWithSameName: unknown;
      [key: string]: unknown;
      }
      }


      But since I want this to be strongly typed, I need to either have the reduce output the object with the correct type or maybe have a type that transforms it, like let's say:



      type Result = TransformType<Main>;

      // Resulting type:
      // type Result = {
      // foo: SameFoo;
      // bar: SameBar;
      // };


      So I can do something like:



      type Result = TransformType<Main>;
      const result: Result = Object.keys(main).reduce(..., {} as Result);


      I hope this is clearer, I know this is a very edge use case.



      Thanks in advance for the help.







      typescript typescript-typings






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Dec 29 '18 at 2:10









      Eric.MEric.M

      313519




      313519
























          1 Answer
          1






          active

          oldest

          votes


















          1














          So, I think you're looking for something like this:



          function transform<T extends Record<keyof T, { propertyWithSameName: unknown }>>(
          obj: T
          ) {
          return (Object.keys(obj) as Array<keyof T>).reduce(
          (acc, k) => (acc[k] = obj[k].propertyWithSameName, acc),
          {} as {
          [K in keyof T]: T[K]['propertyWithSameName'];
          });
          }

          const result = transform(main);
          // const result: {
          // foo: SameFoo;
          // bar: SameBar;
          // }


          Basically the TransformType<> you want is a mapped type that iterates over all the properties and performs a lookup of the propertyWithSameName for each one. Specifically, if the object is of type T, you want {[K in keyof T]: T[K]['propertyWithSameName'];}). Note that you need to constrain T to a type like Record<keyof T, {propertyWithSameName: unknown}>, which is similar to your WhatIKnowAboutTheObject: a Record<K, V> is an object with keys K and values V. So that constraint says "T is a type whose properties must extend {propertyWithSameName: unknown}, or "T's properties must themselves have a propertyWithSameName property".



          I'm not sure if I really like the weird reduce() function I put inside transform() so feel free to change that if you want, but hopefully you get the idea how the typings should look.



          Okay, hope that helps. Good luck!






          share|improve this answer
























          • Yeah, I got it. It works perfectly. This also does the trick: type Transform<T extends Record<keyof T, { propertyWithSameName: unknown }>> = { [K in keyof T]: T[K]['propertyWithSameName'] };

            – Eric.M
            Dec 29 '18 at 12:48











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53966147%2fcreate-an-object-type-based-on-properties-with-same-name-from-multiple-objects-i%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          So, I think you're looking for something like this:



          function transform<T extends Record<keyof T, { propertyWithSameName: unknown }>>(
          obj: T
          ) {
          return (Object.keys(obj) as Array<keyof T>).reduce(
          (acc, k) => (acc[k] = obj[k].propertyWithSameName, acc),
          {} as {
          [K in keyof T]: T[K]['propertyWithSameName'];
          });
          }

          const result = transform(main);
          // const result: {
          // foo: SameFoo;
          // bar: SameBar;
          // }


          Basically the TransformType<> you want is a mapped type that iterates over all the properties and performs a lookup of the propertyWithSameName for each one. Specifically, if the object is of type T, you want {[K in keyof T]: T[K]['propertyWithSameName'];}). Note that you need to constrain T to a type like Record<keyof T, {propertyWithSameName: unknown}>, which is similar to your WhatIKnowAboutTheObject: a Record<K, V> is an object with keys K and values V. So that constraint says "T is a type whose properties must extend {propertyWithSameName: unknown}, or "T's properties must themselves have a propertyWithSameName property".



          I'm not sure if I really like the weird reduce() function I put inside transform() so feel free to change that if you want, but hopefully you get the idea how the typings should look.



          Okay, hope that helps. Good luck!






          share|improve this answer
























          • Yeah, I got it. It works perfectly. This also does the trick: type Transform<T extends Record<keyof T, { propertyWithSameName: unknown }>> = { [K in keyof T]: T[K]['propertyWithSameName'] };

            – Eric.M
            Dec 29 '18 at 12:48
















          1














          So, I think you're looking for something like this:



          function transform<T extends Record<keyof T, { propertyWithSameName: unknown }>>(
          obj: T
          ) {
          return (Object.keys(obj) as Array<keyof T>).reduce(
          (acc, k) => (acc[k] = obj[k].propertyWithSameName, acc),
          {} as {
          [K in keyof T]: T[K]['propertyWithSameName'];
          });
          }

          const result = transform(main);
          // const result: {
          // foo: SameFoo;
          // bar: SameBar;
          // }


          Basically the TransformType<> you want is a mapped type that iterates over all the properties and performs a lookup of the propertyWithSameName for each one. Specifically, if the object is of type T, you want {[K in keyof T]: T[K]['propertyWithSameName'];}). Note that you need to constrain T to a type like Record<keyof T, {propertyWithSameName: unknown}>, which is similar to your WhatIKnowAboutTheObject: a Record<K, V> is an object with keys K and values V. So that constraint says "T is a type whose properties must extend {propertyWithSameName: unknown}, or "T's properties must themselves have a propertyWithSameName property".



          I'm not sure if I really like the weird reduce() function I put inside transform() so feel free to change that if you want, but hopefully you get the idea how the typings should look.



          Okay, hope that helps. Good luck!






          share|improve this answer
























          • Yeah, I got it. It works perfectly. This also does the trick: type Transform<T extends Record<keyof T, { propertyWithSameName: unknown }>> = { [K in keyof T]: T[K]['propertyWithSameName'] };

            – Eric.M
            Dec 29 '18 at 12:48














          1












          1








          1







          So, I think you're looking for something like this:



          function transform<T extends Record<keyof T, { propertyWithSameName: unknown }>>(
          obj: T
          ) {
          return (Object.keys(obj) as Array<keyof T>).reduce(
          (acc, k) => (acc[k] = obj[k].propertyWithSameName, acc),
          {} as {
          [K in keyof T]: T[K]['propertyWithSameName'];
          });
          }

          const result = transform(main);
          // const result: {
          // foo: SameFoo;
          // bar: SameBar;
          // }


          Basically the TransformType<> you want is a mapped type that iterates over all the properties and performs a lookup of the propertyWithSameName for each one. Specifically, if the object is of type T, you want {[K in keyof T]: T[K]['propertyWithSameName'];}). Note that you need to constrain T to a type like Record<keyof T, {propertyWithSameName: unknown}>, which is similar to your WhatIKnowAboutTheObject: a Record<K, V> is an object with keys K and values V. So that constraint says "T is a type whose properties must extend {propertyWithSameName: unknown}, or "T's properties must themselves have a propertyWithSameName property".



          I'm not sure if I really like the weird reduce() function I put inside transform() so feel free to change that if you want, but hopefully you get the idea how the typings should look.



          Okay, hope that helps. Good luck!






          share|improve this answer













          So, I think you're looking for something like this:



          function transform<T extends Record<keyof T, { propertyWithSameName: unknown }>>(
          obj: T
          ) {
          return (Object.keys(obj) as Array<keyof T>).reduce(
          (acc, k) => (acc[k] = obj[k].propertyWithSameName, acc),
          {} as {
          [K in keyof T]: T[K]['propertyWithSameName'];
          });
          }

          const result = transform(main);
          // const result: {
          // foo: SameFoo;
          // bar: SameBar;
          // }


          Basically the TransformType<> you want is a mapped type that iterates over all the properties and performs a lookup of the propertyWithSameName for each one. Specifically, if the object is of type T, you want {[K in keyof T]: T[K]['propertyWithSameName'];}). Note that you need to constrain T to a type like Record<keyof T, {propertyWithSameName: unknown}>, which is similar to your WhatIKnowAboutTheObject: a Record<K, V> is an object with keys K and values V. So that constraint says "T is a type whose properties must extend {propertyWithSameName: unknown}, or "T's properties must themselves have a propertyWithSameName property".



          I'm not sure if I really like the weird reduce() function I put inside transform() so feel free to change that if you want, but hopefully you get the idea how the typings should look.



          Okay, hope that helps. Good luck!







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Dec 29 '18 at 3:19









          jcalzjcalz

          23.5k22142




          23.5k22142













          • Yeah, I got it. It works perfectly. This also does the trick: type Transform<T extends Record<keyof T, { propertyWithSameName: unknown }>> = { [K in keyof T]: T[K]['propertyWithSameName'] };

            – Eric.M
            Dec 29 '18 at 12:48



















          • Yeah, I got it. It works perfectly. This also does the trick: type Transform<T extends Record<keyof T, { propertyWithSameName: unknown }>> = { [K in keyof T]: T[K]['propertyWithSameName'] };

            – Eric.M
            Dec 29 '18 at 12:48

















          Yeah, I got it. It works perfectly. This also does the trick: type Transform<T extends Record<keyof T, { propertyWithSameName: unknown }>> = { [K in keyof T]: T[K]['propertyWithSameName'] };

          – Eric.M
          Dec 29 '18 at 12:48





          Yeah, I got it. It works perfectly. This also does the trick: type Transform<T extends Record<keyof T, { propertyWithSameName: unknown }>> = { [K in keyof T]: T[K]['propertyWithSameName'] };

          – Eric.M
          Dec 29 '18 at 12:48


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53966147%2fcreate-an-object-type-based-on-properties-with-same-name-from-multiple-objects-i%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Mossoró

          Error while reading .h5 file using the rhdf5 package in R

          Pushsharp Apns notification error: 'InvalidToken'