Reputation: 2290
Assume I have some property in my store that is being array of some type MyType
and decorated with observable:
class MyStore {
@observable array
}
I know that in normal world this should be an Array<MyType>
. But when I'm declaring it in this way,
class MyStore {
@observable array: Array<MyType>
}
then I lose the method .remove(item: MyType)
. On the other hand, if I'm declaring it with IObservableArray<MyType>
,
class MyStore {
@observable array: IObservableArray<MyType>
}
then I lose a possibility to legally assign an Array<MyType>
values to this prop (under legally I mean assigning without construction ... as IObservableArray<MyType>
- disadvantages of this method are too obvious: a lot of unnecessary code, the type should be imported whenever it used, etc.)
I also tried to use union and intersection types:
Array<MyType> & IObservableArray<MyType>
) produces an error during assigning an Array<MyType>
value to this prop: Property 'spliceWithArray' is missing in type MyType
.Array<MyType> | IObservableArray<MyType>
) still causes lost of method .remove(item: MyType)
.Am I missing or misunderstanding something? Is there any legal way to defeat it? Thank you all in advance!
By the way, the mobx
version I'm using is 4
, because it is necessary for me to support old iPads, unfortunately
Upvotes: 2
Views: 1528
Reputation: 5396
You need to use the next syntax, this won't generate any TS errors. And you can safely use methods of both Array
and IObservableArray
class MyStore {
readonly array = observable<MyType>([])
@action
getItems() {
api.getItems<MyType[]>().then((response) => this.array.replace(response.data));
}
@action
removeItem(item: MyType) {
this.array.remove(item);
}
}
readonly - as you are mostly not intended to do an assignment for array
property, like this.array = itemsFromServer
replace, remove - methods of IObservableArray
Upvotes: 2
Reputation: 954
How about creating your own tailored type, extending Array class and manually implementing the IObservableArray methods as optional?
Since you are locked to [email protected], there's no problem with the maintaining the interface as the version advances.
it's not ideal but it's the only way I can think of that will allow you to assign Array and also use methods like .remove().
I call the type MyExtendedObservableArray:
import {IArrayChange, IArraySplice, IArrayWillChange, IArrayWillSplice, IInterceptor, IObservableArray, Lambda, observable} from "mobx";
interface MyExtendedObservableArray<T> extends Array<T>{
spliceWithArray?(index: number, deleteCount?: number, newItems?: T[]): T[];
observe?(listener: (changeData: IArrayChange<T> | IArraySplice<T>) => void, fireImmediately?: boolean): Lambda;
intercept?(handler: IInterceptor<IArrayWillChange<T> | IArrayWillSplice<T>>): Lambda;
clear?(): T[];
peek?(): T[];
replace?(newItems: T[]): T[];
find?(predicate: (item: T, index: number, array: IObservableArray<T>) => boolean, thisArg?: any, fromIndex?: number): T | undefined;
findIndex?(predicate: (item: T, index: number, array: IObservableArray<T>) => boolean, thisArg?: any, fromIndex?: number): number;
remove?(value: T): boolean;
move?(fromIndex: number, toIndex: number): void;
toJS?(): T[];
toJSON?(): T[];
}
class MyType{}
let myType = new MyType();
class MyStore {
@observable array: MyExtendedObservableArray<MyType> = [myType]
// no TSC compilation error
}
Upvotes: 1