Skip to content

Proposal to change this.props inference based on props and defaultProps. #29105

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

Closed
5 tasks
azizhk opened this issue Dec 20, 2018 · 2 comments
Closed
5 tasks
Labels
Question An issue which isn't directly actionable in code

Comments

@azizhk
Copy link
Contributor

azizhk commented Dec 20, 2018

Search Terms

defaultProps, react, jsx

Suggestion

Currently while defining defaultProps we define our component something like this:

interface ABCProps {
  requiredProp: number;
  notRequiredProp: number; // Need to remember not to add ?
}

class ABC extends React.PureComponent<ABCProps> {
  static defaultProps = {
    notRequiredProp: 1
  }
  render () {
    // By not addiing ? in Props we don't need to check for undefined.
    const { notRequiredProp } = this.props
    return (
      <div>{notRequiredProp + 1}</div>
    )
  }
}

But if we need to use ABCProps somewhere else, maybe as a part of parent component or if we create an object of type ABCProps, we will need to define the notRequiredProp as well.

const a: ABCProps = {
  requiredProp: 1,
  notRequiredProp: 2 // This is needed.
}

We can have two options:

  1. Define ABCProps' optional props with ? and have component instances this.props be derived from ABCProps and defaultProps. (Breaking change)
interface ABCProps {
  requiredProp: number;
  notRequiredProp?: number; // ? added
}

class ABC extends React.PureComponent<ABCProps> {
  static defaultProps = {
    notRequiredProp: 1
  }
  render () {
    // this.props here !== ABCProps as is
    // typeof this.props === {
    //   [k in keyof ABCProps]: ABC.defaultProps[k] ? NonUndefined<ABCProps[k]> :  ABCProps[k]
    // }
    const { notRequiredProp } = this.props
    return (
      <div>{notRequiredProp + 1}</div>
    )
  }
}
  1. Define ABCProps' optional props without ? but have ABC["props"] be a modified version of ABCProps such that it makes the keys present in defaultProps as optional.
interface ABCProps {
  requiredProp: number;
  notRequiredProp: number; // Need to remember not to add ?
}

class ABC extends React.PureComponent<ABCProps> {
  static defaultProps = {
    notRequiredProp: 1
  }
}

// typeof ABC["props"] === {
//   [k in keyof ABCProps]: ABC.defaultProps[k] ? NonUndefined<ABCProps[k]> :  ABCProps[k]
// }

// typeof ABC["props"] !== ABCProps as is

const a: ABC["props"] = {
  requiredProp: 1
}

Use Cases & Examples

Should be able to reuse a Component's Props without having to define optional props as well.

Checklist

My first option would be a breaking change as people have started following advice from https://github.com/sw-yx/react-typescript-cheatsheet#typing-defaultprops.

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Maybe related: #28954
cc: @Kovensky because you are awesome.

@weswigham
Copy link
Member

If you're looking for a way to name your component's external props interface without repeating yourself, you want to do something like:

import React from "react";

interface ABCPropsInternal { // Shape of the props used within the component
    requiredProp: number;
    notRequiredProp: number;
}

class ABC extends React.PureComponent<ABCPropsInternal> {
    static defaultProps = {
        notRequiredProp: 1
    }
    render() {
        // By not addiing ? in Props we don't need to check for undefined.
        const { notRequiredProp } = this.props
        return (
            <div>{ notRequiredProp + 1}</div>
      )
    }
  }

type ABCProps = JSX.LibraryManagedAttributes<typeof ABC, ABCPropsInternal>; // Calculates external props shape

const props: ABCProps = {
    requiredProp: 0
};

const component = <ABC {...props} />;

@weswigham weswigham added the Question An issue which isn't directly actionable in code label Dec 20, 2018
@azizhk
Copy link
Contributor Author

azizhk commented Dec 20, 2018

Thank you so much.

@azizhk azizhk closed this as completed Dec 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

2 participants