Tuesday, October 17, 2017

Jest test fails after upgrading to React 16



Made it work by changing the shallow to mount:




Have to learn the difference of mount vs shallow.


Happy Coding!

Monday, October 16, 2017

ts-jest Cannot find name 'test'




There are two ways to fix that. One, import 'jest' directly:




Another way is to put the jest type in tsconfig.json:



Happy Coding!

Thursday, October 12, 2017

React 16 now allows rendering with no root element

This code:
    render() {
        return (
            <div>
                <h1>Hello world!</h1>
                <div>Welcome to hot-reloading React written in TypeScript! {this.state.count}</div>
            </div>
        );
    }


Can now be rendered without the root element (e.g., div) in React 16:
    render() {
        return ([
                <h1>Hello world!</h1>,
                <div>Welcome to hot-reloading React written in TypeScript! {this.state.count}</div>

        ]);
    }


Note the use of array above. This isn't allowed yet though:







Happy Coding!

Monday, July 31, 2017

Redux combineReducers compiler error

If a Redux action is added with properties other than the type property, here it's payload..

export interface UserActions extends Action {
    type: UserKind;
    payload: UserPayload;
}

..TypeScript will raise an error on combineReducers:



To fix the compilation error, make the Redux action property be optional:

export interface UserActions extends Action {
    type: UserKind;
    payload?: UserPayload;
}


Result:




However, TypeScript won't be able to catch missed properties, it won't raise an error that we didn't pass the payload property on User 6:




To fix that, remove the optional indicator on Redux action:

export interface UserActions extends Action {
    type: UserKind;
    payload: UserPayload;
}


Result, TypeScript is now able to catch missed properties:




However, we are back to this error on combineReducers:




To comply with combineReducers requirement of Reducer actions containing just a type property only, create another interface that has optional properties (e.g., payload), and use that for the Redux reducer's action parameter (UserActionsNoPayload). And then on UserActions, inherit UserActionsNoPayload from UserActions:



Now, no more combineReducers compilation error, and the compiler is still able to catch missed properties:




Here are the TypeScript definitions for the routeToUser:

export interface StateProps {
    user: Dto.Client.User;
    component: Component;
    counter: Dto.Client.Counter;
}


export interface ActionProps {
    routeToUser: UserDispatcher;
    doCounter: CounterDispatcher;
}


interface Props extends StateProps, ActionProps {
}


export type Dispatcher = (action: UserActions | CounterActions) => void;
export type UserDispatcher = (action: UserActions) => void;
export type CounterDispatcher = (action: CounterActions) => void;


export default class ReduxFirstRouterApp extends React.Component<Props, {}> {



And here is how are the states and dispatchers are mapped as properties to a component via Redux's connect:
const mapStateToProps = ({user, component, counter}: StateProps) => ({user, component, counter});

const mapDispatchToProps = (dispatch: Dispatcher): ActionProps => ({
    routeToUser: (action: UserActions) => dispatch(action),
    doCounter: (action: CounterActions) => dispatch(action)
});

this.AppContainer = connect(mapStateToProps, mapDispatchToProps)(ReduxFirstRouterApp);


Happy Coding!


P.S.

At first, I tried creating UserActions with complete properties, and then made UserActionsNoPayload inherits UserActions and define payload as optional on UserActionsNoPayload; however, it's a compiler error:


Sunday, July 23, 2017

Inline destructuring

Found out a neat ES6 functionality, it can do destructuring of object right on parameters itself.

Below is how it is done on TypeScript:

function greetNoDestructuring(dto: {name: string, favoriteNumber: number}): void {    
    console.log(dto.name);
    console.log(dto.favoriteNumber);
}

function greetManualDestructuring(dto: {name: string, favoriteNumber: number}): void {
    const {name, favoriteNumber} = dto;

    console.log(name);
    console.log(favoriteNumber);
}

function greetInlineDestructuring({name, favoriteNumber}: {name: string, favoriteNumber: number}): void {
    console.log(name);
    console.log(favoriteNumber);
}


greetNoDestructuring({name: 'Kal', favoriteNumber: 7});
greetManualDestructuring({name: 'El', favoriteNumber: 6});
greetInlineDestructuring({name: 'Superman', favoriteNumber: 42});


Happy Coding!

redux-first-router 404



As with all client-side routing, when page is reloaded it will result to 404.

The easiest way to fix that is to indicate fallback page when 404 occurs, this is typically the index.html

On development environment that are using webpack-dev-server, just add the following:

devServer: {
    hot: true,
    proxy: {
        "/api": "http://localhost:3000"
    },
    historyApiFallback: {
        index: "/index.html"
    }
}


Aside from the above, on the fallback page indicate the base href:

<base href="/"/>



Happy Coding!

TypeScript + redux-first-router expected string class/function

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of `App`

When that runtime error occurred, chances is the default is forgotten when importing Link since there is no TypeScript definition for redux-first-router-link yet.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Provider, connect } from 'react-redux';
const Link = require('redux-first-router-link');

To fix:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Provider, connect } from 'react-redux';
const Link = require('redux-first-router-link').default;


Happy coding!