TypeScript strictPropertyInitialization should be turned on

Finally, TypeScript with its version 2.7 brings more rigidity around class properties. For many years, it was possible to define class’ properties without initializing them at the declaration level, neither in the constructor.

Before 2.7, the only difference between an optional and a non optional class’s property was that optional could receive the value of undefined while the other one was undefined until a value was set. After initialized, the non-optional protects the field to receive undefined. However, the case of declaring and not defining the value makes TypeScript less valuable by creating confusion. The nomenclature indicate that a field cannot be undefined but the missing initialization create a limbo where the value is something not allowed.

TypeScript 2.7 brings a new compiler flag: “strictPropertyInitialization”. This new strict flag indicates to TypeScript that any class property must initialize the field at the declaration time or inside the constructor of the class.

Let’s see an example that compile prior to the adoption of strictPropertyInitialization or if this flag is set to false. The following code shows three properties. The “m1” is initialized in the constructor. The “m2” is initialized at declaration. The “m3” is initialized by a call to a method from the constructor. The last example works only without the flag to true.

class C {
    private m1: number;
    private m2: string = "2";
    private m3: boolean;

    public constructor() {
        this.m1 = 1;
        this.init();
    }
    private init():void {
        this.m3 = true;
    }
}

The problem with initializing in a method is the lack of guarantee of invocation. The call to the method might be immediate or might be under a condition that make it not initialize or to initialize partially its properties. TypeScript can perform a deeper analysis if it concentrates on the each field and under a single method — the constructor.

Let’s examine a second example where the compiler catches a missing initialization.

class C {
    private m1: number;
    private m2: string = "2";
    private m3: boolean;

    public constructor(b: boolean) {
        this.m1 = 1;
        if (b) {
            this.m3 = true;
        }   
    }
}

The second example initialize the field “m3” but not in every code path. TypeScript detects that the field might not be initialized, hence doesn’t compile.

An important detail is the flag enters in action when TypeScript configures the strickNullChecks to true. Otherwise, TypeScript accepts undefined without mentioning optional. The combination of strict flags, strickNullChecks and strictPropertyInitialization works hand in hand to reduce potential undesired undefined value for field doesn’t mention the possibility of undefined.

Creating Test with Jest and TypeScript wiht describe, beforeEach and it

Jest provides an easy structure to organize unit tests. It consists of blocks a function imbricated. Each function is a division of a test but not a test itself. The test is inside the function “it”. Here is an example:

describe("Test Class A", () => {
    describe("method 1", () => {
        describe("when parameter a < 0", () => {
            it("throwns an exception", () => {
            });
        });
        describe("when parameter a == 0", () => {
            it("returns 0", () => {
            });
        });
        describe("when parameter a > 0", () => {
            it("returns xyz", () => {
            });
        });
    });
});

The structure is a little bit convoluted but enforces a logical way to divide test and to create very small functions which are easier to maintain. The idea is to strive to have one assertion by test (by “it” function).

Another particularity of the describe function is that since it is a function it creates a closure where variables can live. This allows sharing variables between children functions. A distinction is that it’s alright to declare variables to be shared at the beginning of the describe block, but not to assign. The reason is to respect the order of execution, initialization must be set in the special function “beforeEach” or “beforeAll” which are executed before the subsequent block (describe or it). Here is the same code with an object used in each test.

describe("Test Class A", () => {
    let myObj: ObjectType1;
    describe("method 1", () => {
        beforeEach(() => {
            moObj = new ObjectType1();
        });
        describe("when parameter a < 0", () => {
            it("throwns an exception", () => {
            });
        });
        describe("when parameter a == 0", () => {
            it("returns 0", () => {
            });
        });
        describe("when parameter a > 0", () => {
            it("returns xyz", () => {
            });
        });
    });
});

It might sound very easy and logical, but you may be in a situation that you think that something is wrong — that beforeEach are executed after you test! If this occurs, double check that you do not have an exception thrown in the beforeEach that short-circuit the remaining of the beforeEach code. Double check as well if there is a code assigned directly to a describe block that might be executed out of order.

Strongly Typed Mock with TypeScript and Jest

TypeScript strongly typed nature help reducing the number of tests but unit tests will always be needed to test logic. Jest comes for free when using the React ecosystem and the project “create-react-app” which is also available with TypeScript as the transpiler. In this article, we will see a way to mock an interface that got injected into a class in a strongly typed fashion.

Before getting too far into the detail of the implementation, here is a basic interface that a class use in the application and a class that uses that interface by injection to another class. The goal will be to unit test the class that receives the injected interface. We want to abstract the implementation of the concrete injected class and rely on mocking the interface with Jest.

interface IClassToInject {
    run(): boolean;
}
class ClassToInject implements IClassToInject {
    public run(): boolean {
        return Math.random() >= 0.5;
    }
}
class ClassToTest {
    constructor(private injectedClass: IClassToInject) { }
}

const myClass = new ClassToTest(new ClassToInject());

The idea will be to use jest.Mock which is generic. The problem that we want to have Jest using the same object but not the real type. The idea is to have Jest using the same structure but with the type swapped to use Jest’s stub. TypeScript type mapping can be handy in a situation where we want to preserve the structure but change the type. The type, that I called “Mockify” allows doing exactly this transformation for you. Instead of injecting the interface directly, we inject the Mockify interface. Creating a Mockify version force the definition of each property which you can set to jest.fn(). There is a little of boilerplate that could be automated but overall, the idea is to have the strongly typed nature available. If the interface adds a new member, delete, or rename, the transpiler will raise an error in your test! The notification brings extra validation very soon in the development flow.

The next step is to create a variable that will hold the mocked interface where you can set returned value depending on what is tested in each test. Finally, we set the mock object to the class by injecting the mock by the constructor.

type Mockify<T> = {
    [P in keyof T]: jest.Mock<{}>;
};
let mockInterfaceToInject: Mockify<IClassToInject> = {
    run: jest.fn()
};

mockInterfaceToInject.run.mockReturnValue(false);
const classToTest = new ClassToTest(mockInterfaceToInject);

In this article, we saw that it’s possible to keep an existing interface and to map its structure with new returned values that are from Jest’s mocking framework. It allows keeping in sync with the model and flexible by adding testing capability like giving returned value or count how many time a property is called.

Handling React form with Redux-Form and TypeScript

Most applications require using some form to collect user inputs. So far, I’ve avoided relying on a third-party library when using React and Redux. When we think about it, it’s not hard to send the data to the Redux store, performing some validation and rendering again to React. This loop is executed hundreds of times while the user type values, select values, or move focus out of a field. In the end, another action is sent to submit the data. However, every form of your website needs to repeat this process.

 

Redux-Form is a library that allows handling the burden of having to repeat similar tasks for each of your forms. Redux-Form creates a reducer which is a sibling to your own reducers. This one is dynamically created at creation. The creation occurs in your React container component, during the connect (with React-Redux) phase where this time will be connected to Redux-Form that wraps your component instead of directly wrapping your component. It sounds harder than it is but the documentation is well written. However, one pitfall is that if you are using Redux-Router and push the history object with withRouter at your routing level, you will have to set it again (with withRouter) before exporting manually. For some reason, using the reduxForm functions removes the propagation of this historic property downward.

 

The library works as advertised. It has some nice features, e.g. to know which field changed, got touched, which error to which field, as well as the possibility to reset back to the initial values. Errors are handled in two different ways, letting you choose if you want to set the validation at each input field or at the form level. In both cases, you can cross-validate values between input fields.

 

If you are using TypeScript, you will soon realize that the type passed to the creation of the Redux-Form will probably be different from the type you pass to the component that will hold your form. The reason is that you want to have Redux-Form to handle only the writable properties. This is not an issue; the property type of your component can contain the form fields as well as other fields. In my case, when the Redux store calls the component, I found it useful to map the data into two types: one readable and one writable.

 
export interface MyComponentProps extends InjectedFormProps<MyComponentWritableModel, MyComponentDispatch> {    readableValues: MyComponentReadableModel;    
formState: MyComponentWritableModel;
}

The property of the component inherits InjectedFormProps which is the type used by the form. It’s generic to the type you pass in the Redux-Form method as well. Some minor details: I also inherit from a dispatch type where I can add additional actions to be invoked. I also have two properties, which are readableValue and formState. The first one is used to display information from the Redux state to the form in a read-only fashion. It can also be used for validation of specific values that are not editable. The second property is a copy of the form state that is a strongly typed accessible data of the form. The property allows usage of the data in your component for comparison or for validation.

TypeScript is great because it enforces type. Redux-Form works with TypeScript and has a definition type. However, most of its core concepts rely on strings which make it not as great. For example, to connect a field, you need to specify the name of the property you want to bind. You can go deep into the object by specifying the sub-property with a dot.

Field name="myPropertyInsideWritableObject.CanGoDeep"

The second drawback is that every value entered in fields are pushed back by action in Redux as a string. It means that when you receive the information back and it’s time to map the state to the property to connect the information back to the user interface, you will receive an object, but not with the value specified by TypeScript. It’s worth mentioning that the initial values that are passed to Redux-Form can be from any type (number, boolean) and Redux-Form will store them like it is, with the same type. The issue is around persisting when a user changes a value. There is no mechanism to convert automatically to the desired type.

const formInputsValues = state.form[FORM_NAME] as ReduxFormState<MyComponentWritableModel>; // The problem is that form[x] contains only data from the inputs which are string

Redux-Form is built around the concept that errors will be handled with promise, and failure of the promise will cause the form to fail. I’d rather not have the component tightly coupled with the logic and send my information by action and my middleware performs the action. This is unfortunate, and the cleanest way I found was to provide functions that are decoupled from the component, in their files, and attached to the form (or components). However, for a component called “Redux-Form”, I would prefer an option that would let me handle the validation in a middleware through a specific action that could be listened to and then sending another action with the validations.

The validation, when handled at the form level, is also not pretty. For example, returning an empty object means no error, and returning an object with the same structure of the form, but instead of the actual value the error message, is how to pass error message. This is messy with TypeScript. Imagine you have an object with one property that is number. To set an error message, you need to use the same property name but set a string. The structure changing type brings lots of weakness in a code, and since it’s a crucial part of the system, it’s unacceptable. There is a FormErrors that could be used which takes a generic type that seems to be the type of the form’s state. However, the definition doesn’t work well with sub-object.

export type FormErrors<FormData = {}, T = void> = {    
[P in keyof FormData]?: ReactElement<any> | string | ErrorOther<T>;
};

In my current project, we are using Semantic for inputs. The library Redux-Form works with something called Field. It’s well done and allows you to inject your own React stateless component. I was able to build a generic one that mixes custom properties and Redux-Form properties, allowing me to have an error in a popup next to the field, etc.

Finally, I found a bug in using CSSTransition. The form was available twice during the fade animation (this is how CSSTransition works). The issue is that when the form was completely faded out, it destroyed the Redux-Form state causing the fade-in form to have no more state. I used the property destroyOnUnmount to false, and the issue got fixed. The notion of a unique identifier for each form should be there instead of sharing the same form. That being said, the name is configurable, and you can work out a unique name that changes on each mount.

Overall, it’s a good library with some benefits. The main one is that it’s quick to set up. It also has many features, like state in each field (touched, error, warning, value changed, etc.). However, the weakness of the types, the fact that the validation is strongly bound to the React component (functions or promises), and that manual casting is required, make the library not awesome.