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?
Advertisement
Answer
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 || [] : [];
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 || [];