I am trying to create a way to easily generate a type that defines a multitude of key values association with a specific name pattern in the keys.
I have a specific type that is very repetitive, as for any metrics (working on analytics), I have a 4 keys associated.
For example, for the firstPageVisible
metric, I will have firstPageVisibleMetrics
, firstPageVisibleCount
, firstPageVisibleMetricsPerDevices
, firstPageVisibleCountPerDevices
.
But as I have many metrics, I would like to have some sort of factory to make is easier to read.
I was imagining something like :
type DetailedMetric<Type> = (
name: string,
) => {
[`${name}Metrics`]?: Type;
[`${name}Count`]?: number;
[`${name}MetricsPerDevices`]?: PerDeviceData<Type>;
[`${name}CountPerDevices`]?: PerDeviceData<number>;
};
But I am having the error : A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
.
And I cannot find a satisfying way to resolve this.
In the end, I would like to have something that looks like this (or similar) :
type StoryDataType = {
_id: string;
...;
} & DetailedMetric("firstPageVisible")<number> &
DetailedMetric("metric2")<number> &
DetailedMetric("metric3")<number> &
DetailedMetric("metric4")<number> &
...;
CodePudding user response:
You can define DetailedMetrics
like this:
type DetailedMetric<Type, Name extends string> = {
[K in `${Name}Metrics`]?: Type
} & {
[K in `${Name}Count`]?: number
} & {
[K in `${Name}MetricsPerDevices`]?: PerDeviceData<Type>
} & {
[K in `${Name}CountPerDevices`]?: PerDeviceData<number>
}
CodePudding user response:
You could map over a base type and use a relatively new TypeScript feature called Key Remapping allowing you to compute a property key as you are trying to do`.
type Base<T> = {
Metrics?: T;
Count?: number;
MetricsPerDevices?: number;
CountPerDevices?: number;
}
type DetailedMetric<Type> = <N extends string>(
name: N,
) => {
// Remap the name to be our generic `N`.
[Key in keyof Base<Type> as `${N}${Key}`]: Base<Type>[Key];
};
This way you can define new properties in our Base
type and have them automatically carried over.