Reputation: 3892
i want to use immutable js for my object , here is the code :
import {User} from "../../models/user";
import {Map} from "immutable";
export interface State extends Map<string, any> {
user: User,
token: string,
};
const initialState: State = Map<string, any>({
user: null,
token: null,
});
but i have this error :
Error:(11, 7) TS2322:Type 'Map<string, any>' is not assignable to type 'State'.
Property 'user' is missing in type 'Map<string, any>'.
how can i fix that?
Upvotes: 2
Views: 4661
Reputation: 51
I've spent some time recently with this exact problem. While most answers I found suggested switching to Records, I am doing a large refactor and did not want to update all of the data structures in a rather large codebase.
After a lot of searching, I found this github issue that had the answer I was looking for: https://github.com/facebook/immutable-js/issues/683#issuecomment-381089789 (see the last comment.)
Basically, you extend the basic immutable.Map interface to accept your type definition for your specific case.
For your specific case it would look like this:
import {User} from "../../models/user";
import {Map} from "immutable";
// The default Map interface accepts <K,V>: Key, Value.
// Build an interface that also accepts 'T': the shape of your data.
export interface IImmutableMap<T, K, V> extends Map<K, V> {
toJS(): T;
get<I extends keyof T>(key: I & K): T[I] & V;
set<S extends keyof T>(key: S & K, value: T[S] & V): Map<K, V>;
}
// Extend Map to define the shape of your data
export interface IState extends Map<string, any> {
user: User,
token: string,
};
// Pass the shape to your new interface to define a type.
export type TState = IImmutableMap<IState, string, any>;
// Update the type definition on initial state to your type.
const initialState: TState = Map<string, any>({
user: null,
token: null,
});
You can reuse this IImutableMap interface throughout your codebase by creating new interface and type definitions for each specific case.
If you need to create interfaces for other immutable.js data structures, the immutable docs will be invaluable: https://facebook.github.io/immutable-js/docs/#/
Here is a short blog that explains why you might choose not to use a Record data structure: https://blog.mayflower.de/6630-typescript-redux-immutablejs.html
Upvotes: 5
Reputation: 1870
The Map
object does not contain user
and token
properties, so it is not assignable to type State
. So you lose static typing when use Map
.
I strongly recommend to use Record instead of Map:
export interface IState {
user: User,
token: string,
}
export const State = Immutable.Record<IState>({
user: null,
token: null
});
const initialState = new State();
let state = initialState.set('token', '123');
let token = state.get('token');
Unfortunately type definitions from Facebook are somewhat wrong, but if you add Readonly<T>
declarations, you can just read state.token
property:
export interface Instance<T extends Object> {
...
set<K extends keyof T>(key: K, value: T[K]): this & Readonly<T>;
update... : this & Readonly<T>;
...
}
More about Records.
Upvotes: 2