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',

export interface IProfileAction extends Action
    type: ProfileActionType;

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

        [ProfileActionType.PROFILE_DATA]: IProfileData;
}'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

No comments:

Post a Comment