rangle-starter icon indicating copy to clipboard operation
rangle-starter copied to clipboard

Better use of TypeScript with React and Redux

Open SethDavenport opened this issue 9 years ago • 8 comments

(edit: tracking items with a tasklist)

Doing typescript with react is still a bit unconventional, but I think there's a lot of promise there. However the current starter has a few outstanding questions I'd like us to resolve.

  • [x] Drop React.PropTypes in favour of specifying a props interface for all components. Since this is checked at build time instead of runtime, it's a stronger check and makes React.PropTypes redundant for TypeScript projects. Syntax is also cleaner.
  • [x] VSCode gives red squigglies every time a stateless functional component is used in TSX. Need to make the editor use the correct version of TS (in this case 1.8).
  • [ ] TS barfs any time we try to wrap a stateless functional component in a call to react-redux connect. Looks like react-redux needs an overload for it's connect decorator (see comment below). We should contribute a PR to the community typings.
  • [ ] Same as above, but for redux-form's decorator. We should contribute a PR to the community typings.
  • [x] Remove the webpack config hack to suppress certain TS errors. It's no longer needed since 1.8.

SethDavenport avatar Feb 21 '16 00:02 SethDavenport

@bennett000 @yuri @winkerVSbecks @bertrandk @rbrander @andrejkn

SethDavenport avatar Feb 21 '16 00:02 SethDavenport

Current issues:

redux-react's connect typing won't accept a functional stateless component:

ERROR in ./src/containers/App.tsx (73,3): error TS2345: Argument of type '({ children, session, login, logout }: { children: any; session: any; login: any; logout: any; })...' is not assignable to parameter of type 'typeof ElementClass'. Type '({ children, session, login, logout }: { children: any; session: any; login: any; logout: any; })...' provides no match for the signature 'new (props?: any, context?: any): ElementClass'

SethDavenport avatar Feb 21 '16 05:02 SethDavenport

2: Same thing for reduxForm:

ERROR in ./src/components/LoginForm.tsx (79,4): error TS2345: Argument of type '({ handleSubmit, resetForm, isPending, hasError, fields: { username, password, ...' is not assignable to parameter of type 'typeof ElementClass'.

SethDavenport avatar Feb 21 '16 05:02 SethDavenport

@SethDavenport official typings coming soon: https://github.com/reactjs/redux/pull/1413

winkerVSbecks avatar Feb 21 '16 05:02 winkerVSbecks

That's cool - I can work around (1) in the meantime by converting my containers to class components.

However redux-form typings have the same issue. I'm also expecting Radium to have it as well, although I haven't tried it yet. Actually not sure Radium even has typings...

SethDavenport avatar Feb 21 '16 05:02 SethDavenport

@winkerVSbecks - that PR is for redux, which is great. But I'm talking about connect() from react-redux.

  export function connect(mapStateToProps?: MapStateToProps,
                          mapDispatchToProps?: MapDispatchToPropsFunction|MapDispatchToPropsObject,
                          mergeProps?: MergeProps,
                          options?: Options): ClassDecorator;

We need an overload of this that doesn't return ClassDecorator, but rather something that can decorate StatelessComponent<P>

Might make a PR to DefinitelyTyped at some point.

SethDavenport avatar Feb 21 '16 23:02 SethDavenport

@SethDavenport yes, my bad. @bennett000 mentioned that DefinitelyTyped has kind of stalled at this point. Since, Redux is bringing typings into the main repo we should probably do the same for react-redux, etc.

winkerVSbecks avatar Feb 22 '16 00:02 winkerVSbecks

It would be good to include a pass-through property or two (properties provided by the parent component) in e.g. counter-page.tsx, since this takes a long time to puzzle out how to fix the first time. (For me, the solution was to create an IOwnProps interface for them:

interface IState  { tab: string }
interface IDispatch { onTabChange: (any)=>void }
interface IOwnProps { title:string }   
export class YnAppBarView extends Component<IState & IDispatch & IOwnProps, {}> {

... and then set it as ownProps on the connect:

const mapStateToProps =
    (state, props:IOwnProps)=>({
        myProp: state.yadayada      // e.g.
    })

but you may well have a better way to handle this!

estaub avatar Mar 13 '17 19:03 estaub