0

I'm unable to determine how to specify a non-optional component property that is provided via defaultProps if not specified during construction from typescript.

My source:

'use strict';
import * as React from 'react';
import {DOM as dom} from 'react';
import * as ReactDOM from 'react-dom';

interface PropsType {
    requiredString: string,
    optionalString?: string,
};

class MyComponent extends React.Component<PropsType, {}> {
    static defaultProps = {
        requiredString: 'defaultRequiredString',
    };

    render() {
        return dom.div(
            {},
            this.props.requiredString,
            this.props.optionalString || 'defaultOptionalString',
        );
    }
}

ReactDOM.render(React.createElement(MyComponent, {}));

This gives me:

$ tsc base.ts
base.ts(25,50): error TS2345: Argument of type '{}' is not assignable 
to parameter of type 'Attributes & PropsType'.
  Type '{}' is not assignable to type 'PropsType'.
    Property 'requiredString' is missing in type '{}'.

Reading through the React docs (https://facebook.github.io/react/docs/typechecking-with-proptypes.html), I see the following:

The propTypes typechecking happens after defaultProps are resolved, so typechecking will also apply to the defaultProps.

Which leads me to believe this form should be allowed (and indeed, the large codebase I'm trying to port to typescript has this assumption baked in). I'd be happy to use a Partial<> type for defaultProps if that in any way helps.

How do get this working properly in typescript?

  • FYI the type annotation on the initializer is problematic. You are saying that the member is an object that may or may not have a `requiredString` property. I haven't checked to see if that resolves your issue but it's definitely not right – Aluan Haddad Apr 22 '17 at 03:42
  • I think that requiredString should be an optional in this case, declaring defaultProps in component means that you don't need to pass those props so there are not required – niba Apr 23 '17 at 15:04
  • @niba If I mark `requiredString` as optional, then the compiler will rightly complain when I attempt to use it in `render()` without null-checking it first. That does not match the React docs AFAICT. – Christopher Eck Apr 24 '17 at 04:19
  • @AluanHaddad - sorry, I'm unclear which initializer you're referring to here? What specifically isn't right about it? – Christopher Eck Apr 24 '17 at 04:23
  • In `static defaultProps : Partial = {..}`, you are saying that `defaultProps` has the type `Partial<{requiredString, optionalString?}>` that is equivalent to `{requiredString?, optionalString?}` since it is a compatible subtype, the assignment succeeds but it loses information. In other words, the type of the initializer is equivalent to `PropTypes` but you have suppressed that. – Aluan Haddad Apr 24 '17 at 04:25
  • @AluanHaddad - that seems to be the currently accepted form on SO: http://stackoverflow.com/questions/37282159/default-property-value-in-react-component-using-typescript. – Christopher Eck Apr 24 '17 at 05:00
  • I am just telling you what the code says. It says that `requiredString` may not exist in `defaultProps`. In the linked question they are trying to avoid providing a default value for non-optional props so they are using partial. I would not specify the type at all. – Aluan Haddad Apr 24 '17 at 05:04
  • Thanks. I'll update the code to untype the defaultProps and show that it doesn't solve the original problem. – Christopher Eck Apr 24 '17 at 16:42

0 Answers0