-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Design preview: Stateless Functional Components in JSX #5478
Comments
Confirmed hypothesis -- the Delve team hit Problem B |
👍 |
Update - realized that we'd need to define |
✔️ to implement the following:
|
Because even I have a hard time keeping this all straight: Sampleinterface GreeterProps {
name: string;
}
class Greeter extends React.Component<GreeterProps, {}> {
render() {
return <div>Hello, {this.props.name}</div>;
}
}
let SimpleGreeter = ({name = 'world'}) => <div>Hello, {name}</div>; Glossary
Table
|
Enable Stateless Function Components infrastructure which TypeScript supports officially the design details in TypeScript: microsoft/TypeScript#5478 <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/karen-irc/karen/512) <!-- Reviewable:end -->
Enable Stateless Function Components infrastructure which TypeScript supports officially the design details in TypeScript: microsoft/TypeScript#5478 <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/karen-irc/karen/512) <!-- Reviewable:end -->
This work has been done |
@RyanCavanaugh as i understand, now we can use class Child extends React.Component<{},{}>{
doSomething(){
}
render(){
return <div></div>
}
}
class Parent extends React.Component<{},{}>{
componentDidMount(){
this.refs.myChild.doSomething();
}
render(){
return (
<div>
<Child ref={'myChild'} />
</div>
)
}
} right? |
@stepancar I think you'll need to declare a |
@RyanCavanaugh, 1.8 changes |
i think string-based ref is not bad, callback-based ref is more verbose |
@stepancar https://medium.com/@basarat/strongly-typed-refs-for-react-typescript-9a07419f807#.b8po7nqpj 🌹 Feedback appreciated if any :) |
@basarat , thank you! |
Hi there, I apologize for my ignorance, but I just cannot seem to figure out how this works.... As an illustration, lets say I want to make an I've tried pretty much every flavor of the following: interface ExampleProps extends JSX.IntrinsicClassAttributes<div> {
exampleprop: string
}
export const Example = (props: ExampleProps) =>
// See below note for another unrelated issue
<div data-example={props.exampleprop} {...props} />
// Then later on when I render it...
<Example exampleprop='hello'>
This is my example component with the children prop still rendering appropriately
</Example> Regarding the note comment above, is the Any help is greatly appreciated! Thanks in advance 😄 |
@dsifford you can avoid the warnings by using our nightlies As for how to go about your scenario, your current approach seems fine, though if you really don't feel like declaring a type for that, you could use an intersection type: export const Example = (props: JSX.IntrinsicClassAttributes<div> & { exampleprop: string }) =>
<div data-example={props.exampleprop} {...props} /> Personally, I'm a fan of declaring these prop types explicitly as interfaces because it's a little more readable. |
Thanks (again!) for the clarification @DanielRosenwasser I'm getting this error when I try to declare the prop types like in my above example: I figured I was just doing it incorrectly. Any ideas? |
Sorry, you probably wanted |
Pre-reading
JSX in TypeScript refresher: #3203
Original issue: #4861
Announcement: https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html
Docs: https://facebook.github.io/react/docs/reusable-components.html#stateless-functions
Intro: https://medium.com/@joshblack/stateless-components-in-react-0-14-f9798f8b992d#.d6c0m2mhd
Source: https://github.com/facebook/react/blob/0ef5112e892b2350756400c1d047a2213002bd7d/src/renderers/shared/reconciler/ReactCompositeComponent.js#L155
Detecting Stateless Functional Components (SFCs)
SFCs are invoked with three arguments:
props
,context
, andupdater
. These are the same three arguments passed to component class constructors, so the parameter information is not useful in distinguishing SFCs from classes.SFCs are invoked without
new
whereas classes are invoked withnew
. However, some older React components ignore the fact that they are invoked that way, and may exist with just call signatures, so call vs construct signatures are not useful for SFC detection either.We currently require that the tag expression used in an
<Element />
expression resolve to something with a call or construct signature whose return type is assignable toJSX.ElementClass
. React expects that the result of an invocation of an SFC is the same type that we callJSX.Element
. So we can use the return type of call signatures of three or fewer parameters to distinguish SFCs from classes.Our previous JSX typing design tried to fall back to reasonable behavior when there was only minimal type information in the
JSX
namespace. When bothJSX.Element
andJSX.ElementClass
are empty, however, SFC detection becomes much harder. I propose that a component is only an SFC if it is assignable toJSX.Element
and not assignable toJSX.ElementClass
-- this preserves our good fallback behavior when there isn't a solidreact.d.ts
present, without too much additional complexity.The Element Attributes Type for SFCs
Determining the element attributes type for a SFC is simple: it's the type of the first parameter to the function, or the empty type if the function has zero parameters. However, keep reading.
Resolving the
ref
andkey
madness in props typesCurrent State
TypeScript with React has very annoying problems around the
ref
andkey
attributes.Problem A: the
ref
andkey
attributes are visible when consuming a class, e.g.<Element key="foo" />
is always valid, but the key is never visible inside the class, e.g.this.props.key
is never defined in the classrender
method. This is only slightly annoying as it's hard to use them accidentally in any meaningful fashion.Problem B: More seriously, it's very easy as a component author to make a component whose
props
type lacks thekey
andref
properties, even though those properties should always exist. Because these attributes are optional on JSX elements, we can't even enforce this restriction through the type system.Problem C: Finally, SFCs do not have a
ref
attribute (because there's no instance to point to). This is less serious than problems A and B, but is still a hole.Problem D: The big one. It is valid (and common) to put a
key
attribute on an SFC-based element, but SFCs are never going to bother definingkey
themselves in their parameter type:Proposal
The proposed solution is to add two new types to the
JSX
namespace:IntrinsicAttributes
andIntrinsicClassAttributes
:When determining the element attributes type (the type that determines the allowed attributes of an element), we would intersect the existing type (as determined by the current algorithm) with the properties of either both interfaces (for intrinsic and class-based elements) or just
IntrinsicAttributes
(for SFCs).IntrinsicClassAttributes<T>
would be instantiated with the class instance type forT
.This solves problems A, B, C, and D: it becomes impossible to forget to define
ref
andkey
, it becomes an error to accessref
orkey
fromthis.props
, and it becomes an error to attempt to define aref
attribute when writing a JSX element with a SFC.If desired, we could have only one
IntrinsicAttributes
interface with bothref
andkey
. This would slightly simplify the .d.ts and implementation at the expense of not solving problem C (it would be legal to write an incorrectref
attribute on a SFC JSX element).Decision Points
JSX
namespace isn't filled in:Element
but not assignable toElementClass
IntrinsicAttributes
IntrinsicAttributes
andIntrinsicClassAttributes
/cc @ahejlsberg @billti
The text was updated successfully, but these errors were encountered: