How can I get TypeScript to type-check the spread operator in React props?











up vote
2
down vote

favorite












This code properly flagged in TS:



<MyComponent nonexistentProp="foo" />



This code is not:



<MyComponent { ...{ nonexistentProp: "foo" }} />



It seems trivial for TS to check that improper props are not getting passed in - how can we enable this checking to ensure that we're passing in the expected props?










share|improve this question


















  • 1




    I believe this is not specific to JSX and spread. This actually can be reduced to React.createElement<MyComponentProps>(MyComponent, { nonexistentProp: "foo" }) vs React.createElement<MyComponentProps>(MyComponent, Object.assign({ nonexistentProp: "foo" })) (this is what happens internally).
    – estus
    Nov 20 at 21:43















up vote
2
down vote

favorite












This code properly flagged in TS:



<MyComponent nonexistentProp="foo" />



This code is not:



<MyComponent { ...{ nonexistentProp: "foo" }} />



It seems trivial for TS to check that improper props are not getting passed in - how can we enable this checking to ensure that we're passing in the expected props?










share|improve this question


















  • 1




    I believe this is not specific to JSX and spread. This actually can be reduced to React.createElement<MyComponentProps>(MyComponent, { nonexistentProp: "foo" }) vs React.createElement<MyComponentProps>(MyComponent, Object.assign({ nonexistentProp: "foo" })) (this is what happens internally).
    – estus
    Nov 20 at 21:43













up vote
2
down vote

favorite









up vote
2
down vote

favorite











This code properly flagged in TS:



<MyComponent nonexistentProp="foo" />



This code is not:



<MyComponent { ...{ nonexistentProp: "foo" }} />



It seems trivial for TS to check that improper props are not getting passed in - how can we enable this checking to ensure that we're passing in the expected props?










share|improve this question













This code properly flagged in TS:



<MyComponent nonexistentProp="foo" />



This code is not:



<MyComponent { ...{ nonexistentProp: "foo" }} />



It seems trivial for TS to check that improper props are not getting passed in - how can we enable this checking to ensure that we're passing in the expected props?







reactjs typescript static-analysis






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 20 at 20:20









Luke Williams

1,119826




1,119826








  • 1




    I believe this is not specific to JSX and spread. This actually can be reduced to React.createElement<MyComponentProps>(MyComponent, { nonexistentProp: "foo" }) vs React.createElement<MyComponentProps>(MyComponent, Object.assign({ nonexistentProp: "foo" })) (this is what happens internally).
    – estus
    Nov 20 at 21:43














  • 1




    I believe this is not specific to JSX and spread. This actually can be reduced to React.createElement<MyComponentProps>(MyComponent, { nonexistentProp: "foo" }) vs React.createElement<MyComponentProps>(MyComponent, Object.assign({ nonexistentProp: "foo" })) (this is what happens internally).
    – estus
    Nov 20 at 21:43








1




1




I believe this is not specific to JSX and spread. This actually can be reduced to React.createElement<MyComponentProps>(MyComponent, { nonexistentProp: "foo" }) vs React.createElement<MyComponentProps>(MyComponent, Object.assign({ nonexistentProp: "foo" })) (this is what happens internally).
– estus
Nov 20 at 21:43




I believe this is not specific to JSX and spread. This actually can be reduced to React.createElement<MyComponentProps>(MyComponent, { nonexistentProp: "foo" }) vs React.createElement<MyComponentProps>(MyComponent, Object.assign({ nonexistentProp: "foo" })) (this is what happens internally).
– estus
Nov 20 at 21:43












1 Answer
1






active

oldest

votes

















up vote
0
down vote













I suspect this type checking is subject to the same constraints as regular TypeScript code:



interface Contract {
a: string;
}

const allowed: Contract = {
a: "bc",
};

const notAllowed: Contract = {
a: "bc",
b: "dc",
};

const aboutToBeAllowed = {
a: "bc",
b: "dc",
};

const alsoAllowed: Contract = aboutToBeAllowed;


The problem shown here is that TypeScript has it's limitations, in that it's a structural type system.



It is only able to enforce the constraints that us humans think it should be doing in all cases during an object literal assignment (see notAllowed assignment).



The alsoAllowed case is essentially the same as the notAllowed variant, but it works. This is because the anonymous object satisfies the Contract constraints.



Similarly, in your TSX example, this is essentially the same behavior as regular TypeScript:



interface Props { a: string; };
const MyComponent: React.SFC<Props> = (props) => <div />;

const myCompOk1 = <MyComponent a="ab" />;

const myCompBad1 = <MyComponent a="ab" b="cd" />;

const anonPropsNoExtra = { a: "bc" };
const myCompOk2 = <MyComponent {...anonPropsNoExtra} />;

const anonPropsWithExtra = { a: "bc", b: "cd" };
const myCompOk3 = <MyComponent {...anonPropsWithExtra} />;


I don't believe it's possible for it to enforce it the way you're looking for






share|improve this answer





















    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',
    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%2f53400926%2fhow-can-i-get-typescript-to-type-check-the-spread-operator-in-react-props%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








    up vote
    0
    down vote













    I suspect this type checking is subject to the same constraints as regular TypeScript code:



    interface Contract {
    a: string;
    }

    const allowed: Contract = {
    a: "bc",
    };

    const notAllowed: Contract = {
    a: "bc",
    b: "dc",
    };

    const aboutToBeAllowed = {
    a: "bc",
    b: "dc",
    };

    const alsoAllowed: Contract = aboutToBeAllowed;


    The problem shown here is that TypeScript has it's limitations, in that it's a structural type system.



    It is only able to enforce the constraints that us humans think it should be doing in all cases during an object literal assignment (see notAllowed assignment).



    The alsoAllowed case is essentially the same as the notAllowed variant, but it works. This is because the anonymous object satisfies the Contract constraints.



    Similarly, in your TSX example, this is essentially the same behavior as regular TypeScript:



    interface Props { a: string; };
    const MyComponent: React.SFC<Props> = (props) => <div />;

    const myCompOk1 = <MyComponent a="ab" />;

    const myCompBad1 = <MyComponent a="ab" b="cd" />;

    const anonPropsNoExtra = { a: "bc" };
    const myCompOk2 = <MyComponent {...anonPropsNoExtra} />;

    const anonPropsWithExtra = { a: "bc", b: "cd" };
    const myCompOk3 = <MyComponent {...anonPropsWithExtra} />;


    I don't believe it's possible for it to enforce it the way you're looking for






    share|improve this answer

























      up vote
      0
      down vote













      I suspect this type checking is subject to the same constraints as regular TypeScript code:



      interface Contract {
      a: string;
      }

      const allowed: Contract = {
      a: "bc",
      };

      const notAllowed: Contract = {
      a: "bc",
      b: "dc",
      };

      const aboutToBeAllowed = {
      a: "bc",
      b: "dc",
      };

      const alsoAllowed: Contract = aboutToBeAllowed;


      The problem shown here is that TypeScript has it's limitations, in that it's a structural type system.



      It is only able to enforce the constraints that us humans think it should be doing in all cases during an object literal assignment (see notAllowed assignment).



      The alsoAllowed case is essentially the same as the notAllowed variant, but it works. This is because the anonymous object satisfies the Contract constraints.



      Similarly, in your TSX example, this is essentially the same behavior as regular TypeScript:



      interface Props { a: string; };
      const MyComponent: React.SFC<Props> = (props) => <div />;

      const myCompOk1 = <MyComponent a="ab" />;

      const myCompBad1 = <MyComponent a="ab" b="cd" />;

      const anonPropsNoExtra = { a: "bc" };
      const myCompOk2 = <MyComponent {...anonPropsNoExtra} />;

      const anonPropsWithExtra = { a: "bc", b: "cd" };
      const myCompOk3 = <MyComponent {...anonPropsWithExtra} />;


      I don't believe it's possible for it to enforce it the way you're looking for






      share|improve this answer























        up vote
        0
        down vote










        up vote
        0
        down vote









        I suspect this type checking is subject to the same constraints as regular TypeScript code:



        interface Contract {
        a: string;
        }

        const allowed: Contract = {
        a: "bc",
        };

        const notAllowed: Contract = {
        a: "bc",
        b: "dc",
        };

        const aboutToBeAllowed = {
        a: "bc",
        b: "dc",
        };

        const alsoAllowed: Contract = aboutToBeAllowed;


        The problem shown here is that TypeScript has it's limitations, in that it's a structural type system.



        It is only able to enforce the constraints that us humans think it should be doing in all cases during an object literal assignment (see notAllowed assignment).



        The alsoAllowed case is essentially the same as the notAllowed variant, but it works. This is because the anonymous object satisfies the Contract constraints.



        Similarly, in your TSX example, this is essentially the same behavior as regular TypeScript:



        interface Props { a: string; };
        const MyComponent: React.SFC<Props> = (props) => <div />;

        const myCompOk1 = <MyComponent a="ab" />;

        const myCompBad1 = <MyComponent a="ab" b="cd" />;

        const anonPropsNoExtra = { a: "bc" };
        const myCompOk2 = <MyComponent {...anonPropsNoExtra} />;

        const anonPropsWithExtra = { a: "bc", b: "cd" };
        const myCompOk3 = <MyComponent {...anonPropsWithExtra} />;


        I don't believe it's possible for it to enforce it the way you're looking for






        share|improve this answer












        I suspect this type checking is subject to the same constraints as regular TypeScript code:



        interface Contract {
        a: string;
        }

        const allowed: Contract = {
        a: "bc",
        };

        const notAllowed: Contract = {
        a: "bc",
        b: "dc",
        };

        const aboutToBeAllowed = {
        a: "bc",
        b: "dc",
        };

        const alsoAllowed: Contract = aboutToBeAllowed;


        The problem shown here is that TypeScript has it's limitations, in that it's a structural type system.



        It is only able to enforce the constraints that us humans think it should be doing in all cases during an object literal assignment (see notAllowed assignment).



        The alsoAllowed case is essentially the same as the notAllowed variant, but it works. This is because the anonymous object satisfies the Contract constraints.



        Similarly, in your TSX example, this is essentially the same behavior as regular TypeScript:



        interface Props { a: string; };
        const MyComponent: React.SFC<Props> = (props) => <div />;

        const myCompOk1 = <MyComponent a="ab" />;

        const myCompBad1 = <MyComponent a="ab" b="cd" />;

        const anonPropsNoExtra = { a: "bc" };
        const myCompOk2 = <MyComponent {...anonPropsNoExtra} />;

        const anonPropsWithExtra = { a: "bc", b: "cd" };
        const myCompOk3 = <MyComponent {...anonPropsWithExtra} />;


        I don't believe it's possible for it to enforce it the way you're looking for







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 21 at 5:14









        Alex

        1,9041415




        1,9041415






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400926%2fhow-can-i-get-typescript-to-type-check-the-spread-operator-in-react-props%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

            Berounka

            Sphinx de Gizeh

            Different font size/position of beamer's navigation symbols template's content depending on regular/plain...