'TS2740: Missing properties from type when using spread operator

I have an object mocking out an Angular ActivatedRouteSnapshot ( see definition ). All the props are mocked out. I am then creating another mock object by just spreading the first object's props into the second.

export class AddEditResolverMocks {

    static routeWithId: ActivatedRouteSnapshot = {
        params: { id: 123 },
        data: { entity: EntityTypes.PayBillCycle },
        url: [],
        queryParams: {},
        fragment: '',
        outlet: '',
        component: '',
        routeConfig: null,
        root: new ActivatedRouteSnapshot(),
        parent: new ActivatedRouteSnapshot(),
        firstChild: new ActivatedRouteSnapshot(),
        children: [],
        pathFromRoot: [],
        paramMap: null,
        queryParamMap: null,
    };
    static routeWithoutId: ActivatedRouteSnapshot = {
        ...this.routeWithId,
    };
}

I thought it would bring over all the props, but VSCode seems to complain with:

Type '{ 
    url: UrlSegment[]; 
    params: Params; 
    queryParams: Params; 
    fragment: string; 
    data: Data; 
    outlet: string; 
    component: string | Type<any>; 
    routeConfig: Route; 
}' is missing the following properties from type 'ActivatedRouteSnapshot': 
 - root, 
 - parent, 
 - firstChild, 
 - children, 
 - and 3 more.ts(2740)

When I let VSCode refactor it, the "missing" props are added and the error goes away. So why it not work without explicit initialization? ( feel I am missing something stupid )

I am also surprised that VSCode is allowing a this reference in a static initializer.

UPDATE: Changing this to AddEditResolverMocks :

 static routeWithoutId: ActivatedRouteSnapshot = {
        ...AddEditResolverMocks.routeWithId,
    };

had no effect.

UPDATE 2: Added definition of ActivatedRouteSnapshot in desc as per comment.



Solution 1:[1]

The problem is that these missing properties are not present in the definition of the ActivatedRouteSnapshot class. They are actually getters, not attributes.

However, when there is a getter property without an equivalent setter, the "compiler" assumes this as readonly, which forces you to inform this attribute in the way you are creating the object instance.

But even though you have informed the attributes in this specific instance, the routeWithId variable definition is still ActivatedRouteSnapshot, which does not have these attributes.

For the error to disappear, just remove the definition of the variable:

export class AddEditResolverMocks {

    static routeWithId = {
        params: { id: 123 },
        data: { entity: EntityTypes.PayBillCycle },
        url: [],
        queryParams: {},
        fragment: '',
        outlet: '',
        component: '',
        routeConfig: null,
        root: new ActivatedRouteSnapshot(),
        parent: new ActivatedRouteSnapshot(),
        firstChild: new ActivatedRouteSnapshot(),
        children: [],
        pathFromRoot: [],
        paramMap: null,
        queryParamMap: null,
    };
    static routeWithoutId: ActivatedRouteSnapshot = {
        ...this.routeWithId,
    };
}

Still, I recommend that you don't instantiate these objects this way. The most appropriate is to use the new operator and pass the parameters via the constructor.

Also because the constructor performs some operations when receiving these parameters, something you are not doing when instantiating this way. And the extra attributes you are inserting shouldn't exist in this class.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Edu Müller