How can I get TypeScript to type-check the spread operator in React props?
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
add a comment |
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
1
I believe this is not specific to JSX and spread. This actually can be reduced toReact.createElement<MyComponentProps>(MyComponent, { nonexistentProp: "foo" })
vsReact.createElement<MyComponentProps>(MyComponent, Object.assign({ nonexistentProp: "foo" }))
(this is what happens internally).
– estus
Nov 20 at 21:43
add a comment |
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
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
reactjs typescript static-analysis
asked Nov 20 at 20:20
Luke Williams
1,187928
1,187928
1
I believe this is not specific to JSX and spread. This actually can be reduced toReact.createElement<MyComponentProps>(MyComponent, { nonexistentProp: "foo" })
vsReact.createElement<MyComponentProps>(MyComponent, Object.assign({ nonexistentProp: "foo" }))
(this is what happens internally).
– estus
Nov 20 at 21:43
add a comment |
1
I believe this is not specific to JSX and spread. This actually can be reduced toReact.createElement<MyComponentProps>(MyComponent, { nonexistentProp: "foo" })
vsReact.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
add a comment |
1 Answer
1
active
oldest
votes
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
Ok - interesting, thank you for the background. I'm able to get what I need by refactoring a bit to type-check the object before spreading it into the props.
– Luke Williams
Dec 3 at 19:14
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
Ok - interesting, thank you for the background. I'm able to get what I need by refactoring a bit to type-check the object before spreading it into the props.
– Luke Williams
Dec 3 at 19:14
add a comment |
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
Ok - interesting, thank you for the background. I'm able to get what I need by refactoring a bit to type-check the object before spreading it into the props.
– Luke Williams
Dec 3 at 19:14
add a comment |
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
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
answered Nov 21 at 5:14
Alex
1,9841415
1,9841415
Ok - interesting, thank you for the background. I'm able to get what I need by refactoring a bit to type-check the object before spreading it into the props.
– Luke Williams
Dec 3 at 19:14
add a comment |
Ok - interesting, thank you for the background. I'm able to get what I need by refactoring a bit to type-check the object before spreading it into the props.
– Luke Williams
Dec 3 at 19:14
Ok - interesting, thank you for the background. I'm able to get what I need by refactoring a bit to type-check the object before spreading it into the props.
– Luke Williams
Dec 3 at 19:14
Ok - interesting, thank you for the background. I'm able to get what I need by refactoring a bit to type-check the object before spreading it into the props.
– Luke Williams
Dec 3 at 19:14
add a comment |
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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
1
I believe this is not specific to JSX and spread. This actually can be reduced to
React.createElement<MyComponentProps>(MyComponent, { nonexistentProp: "foo" })
vsReact.createElement<MyComponentProps>(MyComponent, Object.assign({ nonexistentProp: "foo" }))
(this is what happens internally).– estus
Nov 20 at 21:43