Search code examples
typescripttypestypescript2.8

Union Types in Array - TypeScript don't show errors


I am working on menu in Angular 5 with TypeScript 2.8.1 .

I want to add types to validation incoming config, but when i add INCORRECT properties (e.g. undesirableData) nothing happens.

Why TS don't show errors?

Sample Code:

type MenuElement = MenuGroup | MenuItem;

interface MenuGroup {
    id: number;
    name: string;
    icon?: string;
    items: MenuItem[];
}

interface MenuItem {
    id: number;
    name: string;
    url: string;
}

const menuData = [
    {
        id: 1,
        name: 'category',
        icon: 'star',
        items: [
            {
                id: 1,
                name: 'subcategoryOne',
                url: 'urlOne'
            },
            {
                id: 2,
                name: 'subcategoryTwo',
                url: 'urlTwo'
            }
        ]
    },
    {
        id: 2,
        name: 'categoryTwo',
        url: 'urlThree',
        undesirableData: 'text' // undesirable data 
    }
];

export class MainComponent {
    public appMenu: Array<MenuElement>;

    constructor() {
        this.appMenu = this.createMenu(menuData);
    }

    createMenu(menu: Array<MenuElement>) {
        return menu;
    }
}

Solution

  • To validate the object literal you are creating you need to actually specify the type on the const, otherwise the const type will be inferred based on usage.

    const menuData: MenuElement[] = [ ... ];
    

    You can't get an error when you pass call this.createMenu(menuData) because menuData is compatible with MenuElement[] even if it does have some extra fields, object literals are validated for extra properties only on creation. So for example:

    let o  = {
        id: 2,
        name: 'categoryTwo',
        url: 'urlThree',
        undesirableData: 'text'
    }
    let m :MenuItem = o;  //valid structurally compatible
    
    let m2: MenuItem  = { // invalid literal is checked for extra properties
        id: 2,
        name: 'categoryTwo',
        url: 'urlThree',
        undesirableData: 'text' 
    }
    

    You will get errors if there are type incompatibilities if you specify known properties with incompatible types, but you will only get errors for extra properties if you assign the object literal to a variable/parameter/field that is typed explicitly as MenuItem