4

I have a nested json object and define a interface for it

interface Menu {
    [key: string]: string[] | Menu;
}

const menuOnlyForRoles: Menu = {
    site: {
        only: [],
        category: {
            only: ['manager', 'head', 'lead'],
        },
        'floor-section': {
            only: ['head', 'lead'],
        },
    },
};

But when I use it. It appear a warning.

const menuPermissionForKey = menuOnlyForRoles.site || { only: [] };
const rolesCanAccessMenu= menuPermissionForKey.only || [];
                                               ▔▔▔▔
     any
     Property 'only' does not exist on type 'Menu | string[]'.
       Property 'only' does not exist on type 'string[]'

What did I do wrong or missing?

1 Answer 1

3

You didn't do anything wrong per se. TypeScript just cannot infer whether your menuPermissionForKey is a Menu object or a string array.

Ideally, you'd define your Menu type more strictly. Barring that, you can create a type predicate:

interface Menu {
    [key: string]: string[] | Menu;
}

const menuOnlyForRoles: Menu = {
    site: {
        only: [],
        category: {
            only: ['manager', 'head', 'lead'],
        },
        'floor-section': {
            only: ['head', 'lead'],
        },
    },
};

function isMenu(data: Menu | string[]): data is Menu {
    return !Array.isArray(data);
}

const menuPermissionForKey = menuOnlyForRoles.site || { only: [] };
const rolesCanAccessMenu= isMenu(menuPermissionForKey)
                              ? menuPermissionForKey.only || []
                              : [];

Playground link


Alternatively, if you're dealing with static data that is known at compile-time, you can use a const assertion, optionally with the satisfies operator to enforce type-checking at edit time:

interface Menu {
    [key: string]: readonly string[] | Menu;
}

const menuOnlyForRoles = {
    site: {
        only: [],
        category: {
            only: ['manager', 'head', 'lead'],
        },
        'floor-section': {
            only: ['head', 'lead'],
        },
    },
} as const satisfies Menu;

const menuPermissionForKey = menuOnlyForRoles.site || { only: [] };
const rolesCanAccessMenu = menuPermissionForKey.only || [];

Playground link

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.