const types = {
category: 'cat',
size: 'siz'
} as const; // extremely important
type Types = typeof types; // denotes the type of the types object
type TypesValues = Types[keyof Types] // determines values of the types object
type Data = {
[K in TypesValues]: any // mapping all keys to values of types object
}
// utilizing
const dataValues: Data = {
cat: 1,
siz: 2
}
const filterSize: number = dataValues[types.category];
Description
The crucial step here is defining types
with a const assertion, indicating that the object's structure is constant and the inferred types must match precisely. By using const
, typeof types
accurately identifies the keys and values of the object.
Additionally, we define two types, Types
and TypesValues
, for simplicity and better readability, reflecting the content of the types
object.
Lastly, Data
is defined as a map where the keys correspond to all values within the types
object. I have kept values as any
since no specific constraints were specified.
Any modification to the types
object will necessitate updating every instance of the Data
type.
If you require the entire Data
object to contain values of one particular type, like number
, you can achieve this through:
type Data = {
[K in TypesValues]: number // setting all values to numbers
}
Alternatively, in a more versatile approach:
type Data<V> = {
[K in TypesValues]: V // assigning V to all values
}
type DataStr = Data<string>
type DataNum = Data<number>
A comment requested an additional feature; the ability to define types representing subsets of the types
object with different value types. Here’s how that could be implemented:
// expanded object for demonstration
const types = {
category: 'cat',
size: 'siz',
grade: 'grd',
price: 'prc'
} as const;
// repeating the previous two types
type Types = typeof types;
type TypesValues = Types[keyof Types];
// creating distinct value groups
type GroupA = Extract<TypesValues, 'cat' | 'siz'>
type GroupB = Extract<TypesValues, 'grd' | 'prc'>
// formulating a generic type to allow key input via the Keys parameter
type Data<Keys extends PropertyKey, Values> = {
[K in Keys]: Values
}
// combining both types using &
type FinalData = Data<GroupA, number> & Data<GroupB, string>;
// sample usage
const data: FinalData = {
cat: 1, // should be a number
siz: 2, // should be a number
grd: 'A', // should be a string
prc: 'B' // should be a number
}
const categoryValue = data[types.category];