Skip to content

awesome advice from Ferdaber #57

Closed
@ferdaber

Description

@ferdaber

Hi! I'm one of the contributors/maintainers to the @react/types library in DT, and I just have some suggested changes to the docs to ensure that folks who start with TS in React has a smoother experience!

For the section on Function Components:

  • A common pitfall is that these patterns are not supported:
const MyConditionalComponent = ({ shouldRender = false }) => shouldRender ? <div /> : false
const MyArrayComponent = () => Array(5).fill(<div />)
const el = <MyConditionalComponent /> // throws an error
const el2 = <MyArrayComponentt /> // throws an error

This is because due to limitations in the compiler, function components cannot return anything other than a JSX expression or null, otherwise it complains with a cryptic error message saying that the other type is not assignable to Element. Unfortunately just annotating the function type will not help so if you really need to return other exotic types that React supports, you'd need to perform a type assertion:

const MyArrayComponent = () => Array(5).fill(<div />) as any as JSX.Element

For the section on Class Components:

  • I recommend annotating the state class property in addition to adding it as the 2nd generic type parameter in the base class, because it allows better type inference when accessing this.state and also initializing the state. This is because they work in two different ways, the 2nd generic type parameter will allow this.setState() to work correctly, because that method comes from the base class, but initializing state inside the component overrides the base implementation so you have to make sure that you tell the compiler that you're not actually doing anything different.
type MyState = {}
class App extends React.Component<{}, MyState> { state: MyState = {} }

For the section on Typing DefaultProps:

  • I strongly do not recommend annotating defaultProps into a Partial of your Props interface. This causes issues that are a bit complex to explain here with the type inference working with JSX.LibraryManagedAttributes. Basically it causes the compiler to think that when creating a JSX expression with that component, that all of its props are optional. Don't do this! Instead this pattern is recommended:
type Props = Required<typeof MyComponent.defaultProps> & { /* additional props here */ }

export class MyComponent extends React.Component<Props> {
  static defaultProps = {
    foo: 'foo'
  }
}

For the section on Forms and Events:

  • I would just add that inlining the event handler when you don't need to optimize is recommended for better type inference:
// instead of this:
const myHandler = (event: React.MouseEvent<HTMLButtonElement>) => {}
const el = <button onClick={myHandler} />

// do this:
const el = <button onClick={event => {}} />

This tells the compiler that there is no ambiguity to when the handler is being used, and adding function types to the call site allows it to infer the event parameter's types right away.

That's all for now. I can definitely make a PR if y'all agree to these changes!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions