- Notifications
You must be signed in to change notification settings - Fork13.2k
[Master] Type checking JSX children#15160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
…t we won't include in typ-checking
…eScript into master-jsxChildren# Conflicts:#src/compiler/scanner.ts
src/compiler/checker.ts Outdated
| IntrinsicClassAttributes: "IntrinsicClassAttributes" | ||
| }; | ||
| const jsxChildrenPropertyName = "children"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
i would say we should treat this the same way we do withprops instead of hard coding it.
src/compiler/checker.ts Outdated
| function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { | ||
| if (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) { | ||
| const isComparingJsxAttributes = !!(source.flags & TypeFlags.JsxAttributes); | ||
| const containsSynthesizedJsxChildren = !!(source.flags & TypeFlags.ContainsSynthesizedJsxChildren); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
do not think we need this here
src/compiler/diagnosticMessages.json Outdated
| "category":"Error", | ||
| "code":2707 | ||
| }, | ||
| "props.children are specified twice. The attribute named 'children' will be overwritten.": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
name forchildren should be variable, and i would not includeprops here.
… error if you use children without specified such property
# Conflicts:#src/compiler/checker.ts#src/compiler/diagnosticMessages.json
yuit commentedApr 17, 2017
src/compiler/checker.ts Outdated
| let _jsxNamespace: string; | ||
| let _jsxFactoryEntity: EntityName; | ||
| let _jsxElementAttribPropInterfaceSymbol: Symbol; // JSX.ElementAttributesProperty [symbol] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
A comment would be good here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
(A longer one explaining it, that is)
src/compiler/checker.ts Outdated
| // interface ElementAttributesProperty { | ||
| // props: { | ||
| // children?: any; | ||
| // }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Let's figure out some other way to do this - this is too opaque and might not combine well with future work
src/compiler/checker.ts Outdated
| error(attribsPropTypeSym.declarations[0], Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, JsxNames.ElementAttributesPropertyNameContainer); | ||
| return undefined; | ||
| // No interface exists, so the element attributes type will be an implicit any | ||
| _jsxElementPropertiesName = undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Doesn't this mean we'll keep doing this logic repeatedly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yep if we can't find the JSXElement. May be it is better to be empty string to indicate that we already done this
src/compiler/checker.ts Outdated
| // If the call has correct arity, we will then check if the argument type and parameter type is assignable | ||
| const callIsIncomplete = node.attributes.end === node.end; // If we are missing the close "/>", the call isincomplete | ||
| const callIsIncomplete = node.attributes.end === node.end; // If we are missing the close "/>", the call isincoplete |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Undo spelling regression
| } | ||
| exportfunctionisWhiteSpace(ch:number):boolean{ | ||
| exportfunctionisWhiteSpaceLike(ch:number):boolean{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Why the rename?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Because it is not just WhiteSpace but Whitespace and empty line.
RyanCavanaugh commentedApr 20, 2017
GTG after lint fixes |
yuit commentedApr 21, 2017
Thanks@RyanCavanaugh for reviewing 🍰 🍰 |
donaldpipowitch commentedApr 21, 2017
Thank you! This is a great feature. |
RyanCavanaugh commentedApr 24, 2017
@yuit can you write up some minimal docs? I can fill in some details but would like you to write down the basics |
radix commentedJun 10, 2017
The issue that this is meant to resolve has examples that restrict the type of the components in children, but I don't see an example in this PR that does that. Is it actually possible? For example, in the linked issue there is a a use-case where a |
DanielRosenwasser commentedJun 11, 2017
I see you've also been checking on SO:https://stackoverflow.com/questions/44475309/how-do-i-restrict-the-type-of-react-children-in-typescript-using-the-newly-adde I think that the issue here is that all you really get back from a rendered component is a JSX Element. There's not really any information in thre to specify where the element came from. I'm not sure if@yuit or@RyanCavanaugh have had any thoughts on this. |
radix commentedJun 11, 2017
yeah, I have become skeptical that what I'm trying to do is possible, which makes me think that#13618 should not have been closed, since it is specifically about getting type restrictions on what kind of components are used as children of a react component. But I could very well be missing something! |
donaldpipowitch commentedJun 12, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Yeah, this is what I saw inmy tests, too. You can't say something like this: importReact,{Component}from'react';import{render}from'react-dom';classFooextendsComponent<{},void>{render(){return<p>Hello from Foo!</p>;}}interfaceBarProps{children?:Foo|Array<Foo>;}constBar=({ children}:BarProps)=><div>This must be Foo(s):{children}.</div>;render(<div><Bar><Foo/>{/* invalid - is treated as `JSX.Element`, not `Foo` */}</Bar></div>,document.getElementById('app')); |
radix commentedJun 12, 2017
If this really can't be done, then I suggest re-opening#13618, since it's specifically about typing the components used as children (should I comment as such there?) |
Hotell commentedJul 15, 2017
any "last words" on this folks ?
|
zackify commentedOct 2, 2017
Would love to see support for typing children! 👍 |
Uh oh!
There was an error while loading.Please reload this page.
Fix#13618 : type checking children property (for examples and motivation see the original issue) Thanks@joelday for prototyping the feature!
Details
Look for "props" in JSX.ElementChildrenAttribute if there exist a property inside(by default in react.d.ts it is
children) that property name will be used as a name of children property. If such property doesn't exist (e.g using older react.d.ts), we will just check all the children but will NOT attach the type as "children" property.If there existed children in the body of JSX expression, synthesize symbol presenting those children and add them as part of JSX attributes named
children. If there alreadychildrenspecified as attribute of opening element there will be an error indicating that the attribute will get overwritten.When we check each child, we call into
checkExpressionwhat this mean is that all JSX Expression will have type JSX.Element. In the future, by treating as JSX.Element will allow us to easily extends for doing these works[JSX] Cannot declare JSX elements to be in specific types. #13746 orType JSX elements based on createElement function #14729.....Examples
Note: with the
<Fetchuser>example, we can now provide contextual type and give completion as well (see fourslash test)