Intro

When developing a React application using state management system like Redux, you usually use Immutable.JS to make your state not mutable. If you are using VanillaJS you will feel comfortable with the magic string prop name like: get("field_name") and set("field_name", value). However, it is awkward when you are using TypeScript because you will loose the type-checking.

There are many blog posts on the internet that show the way to solve the problem, and most of them are extending a RecordClass. It’s ok if you only read the value, but it does not solve the problem. Please refer to these links for more details:

In this post, I would like to introduce another way to apply type-checking when using Immutable.JS with TypeScript.

Solution

First, please refer to the code below. It shows the pattern to implement Immutable.Map<Key, Value> in typescript.

// define interface or class.
import * as Immutable from "immutable"

// Person interface
export interface Person {
firstName: string
lastName: string
age?: number
}

// Define Person properties.
export declare type PersonProps = keyof Person

// A factory method
function createImmutable<T, K extends keyof T>(o: T) {
return Immutable.Map<K, T[K]>(o)

}

// create an instance of Immutable.Map<"firstName" | "lastName", string | number | undefined>
const immutablePerson = createImmutable<Person, PersonProps>({
  firstName: "Henry",
  lastName: "Nguyen"
})

const firstName: string = immutablePerson.get("firstName") // type-checking fine.
const height = immutablePerson.get("height") // type-checking error

// Define a component state state like this.
interface MyComponentState {
  person: Immutable.Map<PersonProps, Person[PersonProps]> 
}

In the code snippets above we have a factory function:

// A factory method
function createImmutable<T, K extends keyof T>(o: T) {
  return Immutable.Map<K, T[K]>(o)
}

and then, there are 3 steps to define type-checking for Immutable.Map:

1. Define an interface. suck as IPerson

// Person interface
export interface Person {
  firstName: string
  lastName: string
  age?: number
}

2. Define interface’s props type.

// Define Person properties.
export declare type PersonProps = keyof Person

3. Use factory function to create Immutable map object with type-checking

// create an instance of Immutable.Map<"firstName" | "lastName", string | number | undefined>
const immutablePerson = createImmutable<Person, PersonProps>({
  firstName: "Henry",
  lastName: "Nguyen"
})

Conclusion

This is just one out of many ways to solve the problem. If it does not work for you or if you have any better way, please feel free to leave a comment. We can discuss together 😀
Thank you for reading my post 😜

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.