immutable.js - TypeScript och immutable.js-gränssnitt


jag vill använda immutable js för mitt objekt, här är koden:

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,
    });

men jag har det här felet :

Error:(11, 7) TS2322:Type 'Map<string, any>' is not assignable to type 'State'.
  Property 'user' is missing in type 'Map<string, any>'.

hur kan jag fixa det?

Svar #1

Jag har nyligen spenderat lite tid med just detta problem. Medan de flesta svar jag fann föreslog att byta till Records, gör jag en stor omstrukturering och ville inte uppdatera alla datastrukturer i en ganska stor kodbas.

Efter mycket letande hittade jag detta GitHub-ärende som hade svaret jag letade efter: https://github.com/facebook/immutable-js/issues/683#issuecomment-381089789 (se den sista kommentaren.)

I princip utökar du den grundläggande immutable.Map-gränssnittet för att acceptera din typdefinition för ditt specifika fall.

För ditt specifika fall skulle det se ut så här:

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,
});

Du kan återanvända detta IImutableMap-gränssnitt i hela din kodbas genom att skapa nya gränssnitts- och typdefinitioner för varje specifikt fall.

Om du behöver skapa gränssnitt för andra immutable.js-datastrukturer kommer immutable-dokumentationen att vara ovärderlig: https://facebook.github.io/immutable-js/docs/#/

Här är en kort blogg som förklarar varför du kanske väljer att inte använda en Record-datastruktur: https://blog.mayflower.de/6630-typescript-redux-immutablejs.html

Svar #2

Objektet Map innehåller inte user och token egenskaper, så det är inte tilldelningsbart till typen State. Så du förlorar statisk typning när du använder Map.

Jag rekommenderar starkt att använda Record istället för 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');

Tyvärr är typdefinitionerna från Facebook något felaktiga, men om du lägger till Readonly<T>-deklarationer kan du bara läsa state.token-egendomen:

export interface Instance<T extends Object> {
    ...
    set<K extends keyof T>(key: K, value: T[K]): this & Readonly<T>;
    update... : this & Readonly<T>;
    ...
}

Mer om register.