mobx-state-tree icon indicating copy to clipboard operation
mobx-state-tree copied to clipboard

Calling .props on a type that has .preProcessSnapshot doesn't update its snapshot type

Open lorefnon opened this issue 6 years ago • 1 comments

Bug report

  • [X] I've checked documentation and searched for existing issues
  • [X] I've made sure my project is based on the latest MST version

minimal reproduction code

import { types as t, IType, IModelType, ReferenceIdentifier, SnapshotIn, SnapshotOut, Instance} from "mobx-state-tree";

// Define one model

const T2 = t.model({
    id: t.identifier
});

interface IT2 extends Instance<typeof T2> {}

const T$1 = t.model({
    id: t.identifier
}).preProcessSnapshot(s => s);

// Extend the extracted types to add another attribute:

interface ITSnapshotIn extends SnapshotIn<typeof T$1> {
    window: ReferenceIdentifier;
}

interface ITSnapshotOut extends SnapshotOut<typeof T$1> {
    window: ReferenceIdentifier;
}

interface IT extends Instance<typeof T$1> {
    window: IT2;
}

// Use a proxy interface to improve error messages

interface ITRunType extends IType<ITSnapshotIn, ITSnapshotOut, IT> {}

// Extend T$1 with another attribute

const T$2 = T$1.props({
    window: t.late(() => t.reference(T2))
});

// Final exposed type 
export const T: ITRunType = T$2;

Describe the expected behavior

Code should compile

Describe the observed behavior

The last line fails with following error:

Type 'IModelType<{ id: ISimpleType<string>; } & { window: IReferenceType<IModelType<{ id: ISimpleType<string>; }, {}, _NotCustomized, _NotCustomized>>; }, {}, ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; }>>, _NotCustomized>' is not assignable to type 'ITRunType'.
  Types of property 'is' are incompatible.
    Type '(thing: any) => thing is ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; }>> | (ModelInstanceTypeProps<{ id: ISimpleType<string>; } & { window: IReferenceType<IModelType<{ id: ISimpleType<string>; }, {}, _NotCustomized, _NotCustomized>>; }> & IStateTreeNode<IModelType<{ id: ISimpleType<string>; } & { window: IReferenceType<IModelType<{ id: ISimpleType<string>; }, {}, _NotCustomized, _NotCustomized>>; }, {}, ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; }>>, _NotCustomized>>)' is not assignable to type '(thing: any) => thing is ITSnapshotIn | (IT & IStateTreeNode<ITRunType>)'.
      Type predicate 'thing is ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; }>> | (ModelInstanceTypeProps<{ id: ISimpleType<string>; } & { window: IReferenceType<IModelType<{ id: ISimpleType<string>; }, {}, _NotCustomized, _NotCustomized>>; }> & IStateTreeNode<...>)' is not assignable to 'thing is ITSnapshotIn | (IT & IStateTreeNode<ITRunType>)'.
        Type 'ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; }>> | (ModelInstanceTypeProps<{ id: ISimpleType<string>; } & { window: IReferenceType<IModelType<{ id: ISimpleType<string>; }, {}, _NotCustomized, _NotCustomized>>; }> & IStateTreeNode<IModelType<{ id: ISimpleType<string>; } & { window: IReferenceType<IModelType<{ id: ISimpleType<string>; }, {}, _NotCustomized, _NotCustomized>>; }, {}, ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; }>>, _NotCustomized>>)' is not assignable to type 'ITSnapshotIn | (IT & IStateTreeNode<ITRunType>)'.
          Type 'ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; }>>' is not assignable to type 'ITSnapshotIn | (IT & IStateTreeNode<ITRunType>)'.
            Type 'ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; }>>' is not assignable to type 'IT & IStateTreeNode<ITRunType>'.
              Property 'window' is missing in type 'ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; }>>' but required in type 'IT'. ⮐ [2322]

If I inspect the type of SnapshotIn<typeof T$2> I see the following:

type T3 = {
    id: string;
} & Partial<ExtractCFromProps<{
    id: ISimpleType<string>;
}>>

So it appears that once we define a snapshotPreProcessor through .preProcessSnapshot (even one that doesn't actually do anything), any types derived through .props will continue to have the same snapshot type irrespective of any new fields added.

The issue of course goes away if the .preProcessSnapshot invocation is removed (or moved to T3)

I have also observed that if we use types.compose instead of .props the error goes away.

I'd have expected extending through .props and .compose to have been identical operations but it doesn't seem that way.

lorefnon avatar Aug 15 '19 15:08 lorefnon

That's because once you use preProcessSnapshot you are basically declaring what your custom snapshot in type is. Not sure if that can be fixed, hmm

xaviergonz avatar Sep 21 '19 21:09 xaviergonz