Saturday, June 2, 2018

Nameless interface with TypeScript

There are only two hard things in Computer Science: cache invalidation and naming things. -- PHil Karlton


Why give names to action when your action and reducer uses a selector of type, e.g., MyJobAction
export const enum MyJobActionType
{
    MY_JOB               = 'MY_JOB',

    MY_JOB_UI            = 'MY_JOB_UI',
    MY_JOB_DATA_FETCHING = 'MY_JOB_DATA_FETCHING',
    MY_JOB_DATA_FETCHED  = 'MY_JOB_DATA_FETCHED',

}

export type MyJobAction = IMyJobAction | IMyJobUIAction | IMyJobDataFetchingAction | IMyJobDataFetchedAction;

interface IMyJobAction extends Action
{
    type: MyJobActionType.MY_JOB;
    payload?: {
        jobId: 'new' | number;
    };
}

interface IMyJobUIAction extends Action
{
    type: MyJobActionType.MY_JOB_UI;
    ui: React.ComponentClass;
}

interface IMyJobDataFetchingAction extends Action
{
    type: MyJobActionType.MY_JOB_DATA_FETCHING;
}

interface IMyJobDataFetchedAction extends Action
{
    type: MyJobActionType.MY_JOB_DATA_FETCHED;
    data: IPagedDto<IPagedMyJobPostDto>;
}

Reducer:
export const myJobViewModelReducer = produce((
    draft: IMyJobViewModel = {
        view : null,
        model: {
            gridData: no.data
        }
    },
    action: MyJobAction
) =>


Action:
async function loadUI(dispatch: Dispatch<MyJobAction>)
{
    const component = (await import(/* webpackChunkName: 'myJob' */ './')).default;

    const uiAction: MyJobAction = {
        type: MyJobActionType.MY_JOB_UI,
        ui  : component
    };

    await dispatch(uiAction);
}


So don't name things then:
export type MyJobAction =
    {
        type: MyJobActionType.MY_JOB;
        payload?: {
            jobId: 'new' | number;
        };
    }
    |
    {
        type: MyJobActionType.MY_JOB_UI;
        ui: React.ComponentClass;
    }
    |
    {
        type: MyJobActionType.MY_JOB_DATA_FETCHING;
    }
    |
    {
        type: MyJobActionType.MY_JOB_DATA_FETCHED;
        data: IPagedDto<IPagedMyJobPostDto>;
    }
    ;

Are you worried someone might use the wrong payload (e.g., payload, ui, data) when dispatching an action? Don't worry, TypeScript is a smart programming language.




And just like that, TypeScript can infer that only the ui property is present on type: MyJobActionType.MY_JOB_UI




By the way, don't use the Dispatch type definition from redux, use the one from react-redux, it has more comprehensive type-checking. Upgraded to Redux 4, no more type definition problem.


So if you want TypeScript to type-check your direct object parameter to dispatch function, use react-redux's Dispatch type definition instead: Use Redux 4.0 instead, it comes with the correct type definition.



Finally, correct the properties of the object structure that matches type: MyJobActionType.MY_JOB_UI




Less interfaces, less names need to come up with.

Thursday, May 31, 2018

timestamptz is easier to adjust than timestamp

x=# create table z(id int primary key, _timestamp timestamp, _timestamptz timestamptz);
CREATE TABLE
x=# 
x=# insert into z(id, _timestamp, _timestamptz) values (1, '2018-05-04T17:37:00Z', '2018-05-04T17:37:00Z');
INSERT 0 1
x=# 
x=# set timezone to 'Asia/Manila';
SET
x=# select 
x-#   _timestamp, 
x-#  _timestamptz, 
x-#  _timestamp at time zone 'UTC' at time zone 'Japan' as "timestamp in Japan", 
x-#  _timestamptz at time zone 'Asia/Tokyo' "timestamp in Japan",
x-#  _timestamp at time zone 'UTC' at time zone 'Asia/Manila' "timestamptz in Philippines", 
x-#  _timestamptz at time zone 'Asia/Manila' as "timestamptz in Philippines"
x-# from z;
-[ RECORD 1 ]--------------+-----------------------
_timestamp                 | 2018-05-04 17:37:00
_timestamptz               | 2018-05-05 01:37:00+08
timestamp in Japan         | 2018-05-05 02:37:00
timestamp in Japan         | 2018-05-05 02:37:00
timestamptz in Philippines | 2018-05-05 01:37:00
timestamptz in Philippines | 2018-05-05 01:37:00

x=# 
x=# set timezone to 'Asia/Tokyo';
SET
x=# select 
x-#   _timestamp, 
x-#  _timestamptz, 
x-#  _timestamp at time zone 'UTC' at time zone 'Japan' as "timestamp in Japan", 
x-#  _timestamptz at time zone 'Asia/Tokyo' "timestamp in Japan",
x-#  _timestamp at time zone 'UTC' at time zone 'Asia/Manila' "timestamptz in Philippines", 
x-#  _timestamptz at time zone 'Asia/Manila' as "timestamptz in Philippines"
x-# from z;
-[ RECORD 1 ]--------------+-----------------------
_timestamp                 | 2018-05-04 17:37:00
_timestamptz               | 2018-05-05 02:37:00+09
timestamp in Japan         | 2018-05-05 02:37:00
timestamp in Japan         | 2018-05-05 02:37:00
timestamptz in Philippines | 2018-05-05 01:37:00
timestamptz in Philippines | 2018-05-05 01:37:00

Wednesday, May 30, 2018

React readability

Let's say you have this view model controlled by Redux reducer. Its view (React.ComponentClass) property is code-splitted by webpack, so the view is dynamically loaded (e.g., from nested routing by redux-first-router's thunk). Which would require the view be nullable.

export interface IJobFormViewModel
{
    view: React.ComponentClass | null;
    model: IJobFormModel;
}

export interface IJobFormModel
{
    jobId?: number | 'new';

    // lookups
    states: IStateCityDto[];
    durationTypes: IDurationTypeDto[];
    locationTypes: ILocationTypeDto[];

    // form's initial values
    initialValues?: IJobDto;
}

There are three ways the parent component can render the nested component.

Option 1:
const {jobId} = this.props.rootState.jobForm.model;

const JobFormView =
    this.props.rootState.jobForm.view ?
        <this.props.rootState.jobForm.view/>
        :
        <></>;

return <>
    <Helmet>
        <title>My Job Posts</title>
    </Helmet>

    <ReactTable
       ...
    />


    {jobId && JobFormView}

</>;

That's ok, but it's not readily obvious that the JobFormView is a component, it could just be a number, string or date only.


Option 2:
const {jobId} = this.props.rootState.jobForm.model;

const JobFormView = this.props.rootState.jobForm.view || 'span';

return <>
    <Helmet>
        <title>My Job Posts</title>
    </Helmet>

    <ReactTable
       ...
    />


    {jobId && <JobFormView/>}

</>;


Looks good, however the span tag would be included in page's markup whenever the nested view is not yet loaded.

You might be tempted to use this, but this won't work.
const JobFormView = this.props.rootState.jobForm.view || 'React.Fragment';


<React.Fragment> tag is a compiler magic, it will not appear on page's markup. However the following, not only it is a compiler error

const BeeAre = 'br';
const RF = 'React.Fragment';

return <>
    Hello
    <BeeAre/>
    <RF/>
    World
</>;





It would also cause error on browser




Besides 'React.Fragment' is a magic string, yet it does not do any magic, it just makes the markup invalid.

Option 3
const {jobId} = this.props.rootState.jobForm.model;

const JobFormView = this.props.rootState.jobForm.view;

return <>
    <Helmet>
        <title>My Job Posts</title>
    </Helmet>

    <ReactTable
       ...
    />


    {jobId && JobFormView && <JobFormView/>}

</>;


That's the perfect option, not only that the component is obvious, there are no extraneous markup (e.g., span) that would appear on page when the nested view is not yet loaded.

Tuesday, May 29, 2018

ReactTable accessing the type definition

There are two ways to do that.

First approach, import all of the react-table.

import * as ReactTable from 'react-table';

class Something extends.ReactComponent<{}, {}>
{
   private table: ReactTable.Instance;

   public render(): React.ReactNode
   {
      return <>
          <ReactTable.default
             ...
          >
             {(state, makeTable, instance) =>
             {
                 this.table = instance;
                 return makeTable();
             }
          </ReactTable>
      <>;
   }
}

<ReactTable.default ...> is a leaky abstraction though. All the advances in adding syntactic sugars to TypeScript/ES6, and yet some devs still want to leak the abstraction, heretic! Might as well just use de-sugarized import:

const ReactTable = require('react-table');

   // now usage of .default is excusable

   <ReactTable.default


To avoid using the .default directly, just import ReactTable and its type definition separately

import ReactTable, * as ReactTableTypes from 'react-table';

class Something extends.ReactComponent<{}, {}>
{
   private table: ReactTableTypes.Instance;

   public render(): React.ReactNode
   {
      return <>
          <ReactTable
             ...
          >
             {(state, makeTable, instance) =>
             {
                 this.table = instance;
                 return makeTable();
             }
          </ReactTable>
      <>;
   }
}

That's cleaner, you can use ReactTable without the default property. This is possible though:

import ReactTable, * as ReactTableTypes from 'react-table';

class Something extends.ReactComponent<{}, {}>
{
   private table: ReactTableTypes.Instance;

   public render(): React.ReactNode
   {
      return <>
          <ReactTableTypes.default
             ...
          >
             {(state, makeTable, instance) =>
             {
                 this.table = instance;
                 return makeTable();
             }
          </ReactTable>
      <>;
   }
}


But who would do that?

Monday, May 28, 2018

TypeScript is the best for Redux


With the following payload signature..

import { Action } from 'redux';

import { IProfileData } from './model';

export const enum ProfileActionType
{
    PROFILE           = 'PROFILE',
    PROFILE_UI        = 'PROFILE_UI',
    PROFILE_DATA      = 'PROFILE_DATA',
    PROFILE_POST_DATA = 'PROFILE_POST_DATA'
}

export interface IProfileAction extends Action
{
    type: ProfileActionType;

    payload: Partial<{
        [ProfileActionType.PROFILE_UI]: React.ComponentClass;

        [ProfileActionType.PROFILE_DATA]: IProfileData;
    }>;
}


..it's still possible to wrongly choose the correct payload:






And you cannot even pass the correct property as-is:



You must use the null-assertion operator, exclamation mark:




A better way would be is to separate the action data structures for UI and Data, and lump them in an action selector (ProfileAction):

export type ProfileAction = IProfileUIAction | IProfileDataAction;

interface IProfileUIAction extends Action
{
    type: ProfileActionType.PROFILE_UI;
    component: React.ComponentClass;
}

interface IProfileDataAction extends Action
{
    type: ProfileActionType.PROFILE_DATA;
    data: IProfileData;
}

With that, only the component property of ProfileAction will be available for ProfileActionType.PROFILE_UI:



Likewise with ProfileActionType.PROFILE_DATA, only the data property of ProfileAction will be available from ProfileActionType's intellisense.



And that is not just an intellisense feature, it's a language feature. So if you try to get the data property from ProfileAction when the condition (switch case ProfileActionType.PROFILE_UI) is in ProfileActionType.PROFILE_UI, it will not be possible. So awesome!




Likewise when the condition is in ProfileActionType.PROFILE_DATA, you cannot selection action's component property:




You can only choose data property from the action when the condition is in ProfileActionType.PROFILE_DATA:




TypeScript truly feels magical that it can infer the right data structure based on the condition. If you try to select the properties from action outside of switch condition, you can't select the component property neither the data property.




It's also a compiler error:




It's also a compiler error to create an object that does not match from the type's selector:




You can only create an object that matches the type: ProfileActionType.PROFILE_UI

Sunday, May 27, 2018

Postgres timestamp





Happy Coding!

Postgres UTC data type

There's really no type of timestamp with time zone with Postgres. Time zone is not stored, everything is stored as UTC. The time zone is only used for presentation purposes.











Happy Coding!