How to write omit function with proper types in typescript












1















What I ultimately want to do is to create a React HOC that would inject a property defined by a string and return a component without requiring the injected property. In essence though this boils down to a factory function returning an omit function.



As you can see in this example for some reason the type B ends up being 'never'.



const f = <A extends object, B extends keyof A>(arg: B) => (obj: A): Omit<A, B> => {
delete obj[arg]
return obj
}
// TS2345: Argument of type "test" is not assignable to parameter of type 'never'
const a = f('test')
const b = a({ test: 1})
const c = b.test


When I try keyof outside of generic parameter, it seem to be functioning better, but typescript does not infer the return type properly and I do not know how to type it as I do not know how to get the reference to the first string arg that could be used in Omit:



const f = <A extends object>(arg: keyof A) => (obj: A) => {
delete obj[arg]
return obj
}
const a = f('test')
const b = a({ test: 1 })
// Does not infer 'test' is no longer here
const c = b.test


For reference Omit is:



export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>









share|improve this question



























    1















    What I ultimately want to do is to create a React HOC that would inject a property defined by a string and return a component without requiring the injected property. In essence though this boils down to a factory function returning an omit function.



    As you can see in this example for some reason the type B ends up being 'never'.



    const f = <A extends object, B extends keyof A>(arg: B) => (obj: A): Omit<A, B> => {
    delete obj[arg]
    return obj
    }
    // TS2345: Argument of type "test" is not assignable to parameter of type 'never'
    const a = f('test')
    const b = a({ test: 1})
    const c = b.test


    When I try keyof outside of generic parameter, it seem to be functioning better, but typescript does not infer the return type properly and I do not know how to type it as I do not know how to get the reference to the first string arg that could be used in Omit:



    const f = <A extends object>(arg: keyof A) => (obj: A) => {
    delete obj[arg]
    return obj
    }
    const a = f('test')
    const b = a({ test: 1 })
    // Does not infer 'test' is no longer here
    const c = b.test


    For reference Omit is:



    export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>









    share|improve this question

























      1












      1








      1








      What I ultimately want to do is to create a React HOC that would inject a property defined by a string and return a component without requiring the injected property. In essence though this boils down to a factory function returning an omit function.



      As you can see in this example for some reason the type B ends up being 'never'.



      const f = <A extends object, B extends keyof A>(arg: B) => (obj: A): Omit<A, B> => {
      delete obj[arg]
      return obj
      }
      // TS2345: Argument of type "test" is not assignable to parameter of type 'never'
      const a = f('test')
      const b = a({ test: 1})
      const c = b.test


      When I try keyof outside of generic parameter, it seem to be functioning better, but typescript does not infer the return type properly and I do not know how to type it as I do not know how to get the reference to the first string arg that could be used in Omit:



      const f = <A extends object>(arg: keyof A) => (obj: A) => {
      delete obj[arg]
      return obj
      }
      const a = f('test')
      const b = a({ test: 1 })
      // Does not infer 'test' is no longer here
      const c = b.test


      For reference Omit is:



      export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>









      share|improve this question














      What I ultimately want to do is to create a React HOC that would inject a property defined by a string and return a component without requiring the injected property. In essence though this boils down to a factory function returning an omit function.



      As you can see in this example for some reason the type B ends up being 'never'.



      const f = <A extends object, B extends keyof A>(arg: B) => (obj: A): Omit<A, B> => {
      delete obj[arg]
      return obj
      }
      // TS2345: Argument of type "test" is not assignable to parameter of type 'never'
      const a = f('test')
      const b = a({ test: 1})
      const c = b.test


      When I try keyof outside of generic parameter, it seem to be functioning better, but typescript does not infer the return type properly and I do not know how to type it as I do not know how to get the reference to the first string arg that could be used in Omit:



      const f = <A extends object>(arg: keyof A) => (obj: A) => {
      delete obj[arg]
      return obj
      }
      const a = f('test')
      const b = a({ test: 1 })
      // Does not infer 'test' is no longer here
      const c = b.test


      For reference Omit is:



      export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>






      reactjs typescript






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 25 '18 at 9:17









      aocenasaocenas

      5117




      5117
























          1 Answer
          1






          active

          oldest

          votes


















          1














          Since the first function has both type arguments, typescript will try to infer both when that call happens and since there is no inference site for A it will probably infer {} for it, making B never. The way to fix this, is to make B and when the second call occurs infer A, with the constraint that A must have a B key:



          export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>

          const f = <B extends keyof any>(arg: B) => <A extends Record<B, any>>(obj: A): Omit<A, B> => {
          delete obj[arg]
          return obj
          }

          const a = f('test')
          const b = a({ test: 1, other: ""})
          const c = b.test; // error as expected
          const c2 = b.other; // ok





          share|improve this answer


























          • Thank you very much, this helps tremendously. I realised thought I have one more piece in the HOC, that I omitted in the question. Would it be possible to back propagate the A type somehow to the first function call. What I want to do is <B extends keyof any>(arg: B, fn: (arg: A) => void) => .... So basically, I give you attribute name and a function that will take object I will give you later. If that does not make sense I can create new question, my bad I did not realise this will be important.

            – aocenas
            Nov 25 '18 at 18:08













          • @aocenas could you post a new question with the full code ? It would make more sense to see it in full.. the comments is not a good place for a lot of code..

            – Titian Cernicova-Dragomir
            Nov 25 '18 at 18:10











          • Here is the new question, hope it makes sense stackoverflow.com/questions/53470559/…

            – aocenas
            Nov 25 '18 at 18:32











          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%2f53466131%2fhow-to-write-omit-function-with-proper-types-in-typescript%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














          Since the first function has both type arguments, typescript will try to infer both when that call happens and since there is no inference site for A it will probably infer {} for it, making B never. The way to fix this, is to make B and when the second call occurs infer A, with the constraint that A must have a B key:



          export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>

          const f = <B extends keyof any>(arg: B) => <A extends Record<B, any>>(obj: A): Omit<A, B> => {
          delete obj[arg]
          return obj
          }

          const a = f('test')
          const b = a({ test: 1, other: ""})
          const c = b.test; // error as expected
          const c2 = b.other; // ok





          share|improve this answer


























          • Thank you very much, this helps tremendously. I realised thought I have one more piece in the HOC, that I omitted in the question. Would it be possible to back propagate the A type somehow to the first function call. What I want to do is <B extends keyof any>(arg: B, fn: (arg: A) => void) => .... So basically, I give you attribute name and a function that will take object I will give you later. If that does not make sense I can create new question, my bad I did not realise this will be important.

            – aocenas
            Nov 25 '18 at 18:08













          • @aocenas could you post a new question with the full code ? It would make more sense to see it in full.. the comments is not a good place for a lot of code..

            – Titian Cernicova-Dragomir
            Nov 25 '18 at 18:10











          • Here is the new question, hope it makes sense stackoverflow.com/questions/53470559/…

            – aocenas
            Nov 25 '18 at 18:32
















          1














          Since the first function has both type arguments, typescript will try to infer both when that call happens and since there is no inference site for A it will probably infer {} for it, making B never. The way to fix this, is to make B and when the second call occurs infer A, with the constraint that A must have a B key:



          export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>

          const f = <B extends keyof any>(arg: B) => <A extends Record<B, any>>(obj: A): Omit<A, B> => {
          delete obj[arg]
          return obj
          }

          const a = f('test')
          const b = a({ test: 1, other: ""})
          const c = b.test; // error as expected
          const c2 = b.other; // ok





          share|improve this answer


























          • Thank you very much, this helps tremendously. I realised thought I have one more piece in the HOC, that I omitted in the question. Would it be possible to back propagate the A type somehow to the first function call. What I want to do is <B extends keyof any>(arg: B, fn: (arg: A) => void) => .... So basically, I give you attribute name and a function that will take object I will give you later. If that does not make sense I can create new question, my bad I did not realise this will be important.

            – aocenas
            Nov 25 '18 at 18:08













          • @aocenas could you post a new question with the full code ? It would make more sense to see it in full.. the comments is not a good place for a lot of code..

            – Titian Cernicova-Dragomir
            Nov 25 '18 at 18:10











          • Here is the new question, hope it makes sense stackoverflow.com/questions/53470559/…

            – aocenas
            Nov 25 '18 at 18:32














          1












          1








          1







          Since the first function has both type arguments, typescript will try to infer both when that call happens and since there is no inference site for A it will probably infer {} for it, making B never. The way to fix this, is to make B and when the second call occurs infer A, with the constraint that A must have a B key:



          export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>

          const f = <B extends keyof any>(arg: B) => <A extends Record<B, any>>(obj: A): Omit<A, B> => {
          delete obj[arg]
          return obj
          }

          const a = f('test')
          const b = a({ test: 1, other: ""})
          const c = b.test; // error as expected
          const c2 = b.other; // ok





          share|improve this answer















          Since the first function has both type arguments, typescript will try to infer both when that call happens and since there is no inference site for A it will probably infer {} for it, making B never. The way to fix this, is to make B and when the second call occurs infer A, with the constraint that A must have a B key:



          export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>

          const f = <B extends keyof any>(arg: B) => <A extends Record<B, any>>(obj: A): Omit<A, B> => {
          delete obj[arg]
          return obj
          }

          const a = f('test')
          const b = a({ test: 1, other: ""})
          const c = b.test; // error as expected
          const c2 = b.other; // ok






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 25 '18 at 10:04

























          answered Nov 25 '18 at 9:57









          Titian Cernicova-DragomirTitian Cernicova-Dragomir

          67.6k34664




          67.6k34664













          • Thank you very much, this helps tremendously. I realised thought I have one more piece in the HOC, that I omitted in the question. Would it be possible to back propagate the A type somehow to the first function call. What I want to do is <B extends keyof any>(arg: B, fn: (arg: A) => void) => .... So basically, I give you attribute name and a function that will take object I will give you later. If that does not make sense I can create new question, my bad I did not realise this will be important.

            – aocenas
            Nov 25 '18 at 18:08













          • @aocenas could you post a new question with the full code ? It would make more sense to see it in full.. the comments is not a good place for a lot of code..

            – Titian Cernicova-Dragomir
            Nov 25 '18 at 18:10











          • Here is the new question, hope it makes sense stackoverflow.com/questions/53470559/…

            – aocenas
            Nov 25 '18 at 18:32



















          • Thank you very much, this helps tremendously. I realised thought I have one more piece in the HOC, that I omitted in the question. Would it be possible to back propagate the A type somehow to the first function call. What I want to do is <B extends keyof any>(arg: B, fn: (arg: A) => void) => .... So basically, I give you attribute name and a function that will take object I will give you later. If that does not make sense I can create new question, my bad I did not realise this will be important.

            – aocenas
            Nov 25 '18 at 18:08













          • @aocenas could you post a new question with the full code ? It would make more sense to see it in full.. the comments is not a good place for a lot of code..

            – Titian Cernicova-Dragomir
            Nov 25 '18 at 18:10











          • Here is the new question, hope it makes sense stackoverflow.com/questions/53470559/…

            – aocenas
            Nov 25 '18 at 18:32

















          Thank you very much, this helps tremendously. I realised thought I have one more piece in the HOC, that I omitted in the question. Would it be possible to back propagate the A type somehow to the first function call. What I want to do is <B extends keyof any>(arg: B, fn: (arg: A) => void) => .... So basically, I give you attribute name and a function that will take object I will give you later. If that does not make sense I can create new question, my bad I did not realise this will be important.

          – aocenas
          Nov 25 '18 at 18:08







          Thank you very much, this helps tremendously. I realised thought I have one more piece in the HOC, that I omitted in the question. Would it be possible to back propagate the A type somehow to the first function call. What I want to do is <B extends keyof any>(arg: B, fn: (arg: A) => void) => .... So basically, I give you attribute name and a function that will take object I will give you later. If that does not make sense I can create new question, my bad I did not realise this will be important.

          – aocenas
          Nov 25 '18 at 18:08















          @aocenas could you post a new question with the full code ? It would make more sense to see it in full.. the comments is not a good place for a lot of code..

          – Titian Cernicova-Dragomir
          Nov 25 '18 at 18:10





          @aocenas could you post a new question with the full code ? It would make more sense to see it in full.. the comments is not a good place for a lot of code..

          – Titian Cernicova-Dragomir
          Nov 25 '18 at 18:10













          Here is the new question, hope it makes sense stackoverflow.com/questions/53470559/…

          – aocenas
          Nov 25 '18 at 18:32





          Here is the new question, hope it makes sense stackoverflow.com/questions/53470559/…

          – aocenas
          Nov 25 '18 at 18:32




















          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%2f53466131%2fhow-to-write-omit-function-with-proper-types-in-typescript%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

          404 Error Contact Form 7 ajax form submitting

          How to know if a Active Directory user can login interactively

          Refactoring coordinates for Minecraft Pi buildings written in Python