I am able to infer types when I'm not using Record
export const TabsDefinition = {
dimensionDetails: [
{ name: 'general', label: 'General' },
{ name: 'settings', label: 'Settings' },
{ name: 'list', label: 'List' },
],
} as const;
type MyNames = typeof TabsDefinition.dimensionDetails[number]['name'];
With this approach MyNames
is infered as "general" | "settings" | "list"
But I want to use type for array of items - so I created this
type Tab = {
name: string;
label: string;
};
export const TabsDefinition: Record<string, ReadonlyArray<Tab>> = {
dimensionDetails: [
{ name: 'general', label: 'General' },
{ name: 'settings', label: 'Settings' },
{ name: 'list', label: 'List' },
],
} as const;
type MyNames = typeof TabsDefinition.dimensionDetails[number]['name'];
but then MyNames
type is infered as string
CodePudding user response:
When you assign a const object literal to a variable of type Record<string, ReadonlyArray<Tab>>
the information is lost - now the compiler assumes that TabsDefinition is can contain any value conforming to that type.
The solution is to keep the precise type of your object literal, but force TS to type check against Record<string, ReadonlyArray<Tab>>
.
There is an open issue "satisfies" operator to ensure an expression matches some type designed precisely to address that need.
Until it lands in an official release, you can use a constrained identity function:
type Tab = {
name: string;
label: string;
};
function createTabsDefinition <T extends Record<string, ReadonlyArray<Tab>>>(def: T): T {
return def;
}
export const TabsDefinition = createTabsDefinition({
dimensionDetails: [
{ name: 'general', label: 'General' },
{ name: 'settings', label: 'Settings' },
{ name: 'list', label: 'List' },
],
} as const);
type MyNames = typeof TabsDefinition.dimensionDetails[number]['name'];