Reputation: 8590
How would you type this objects in typescript ?
I have one special "datetime" key that is a Date, the rest of the keys are numbers. But I don't know in advance which keys will be set on each object. Examples values:
type Metrics = ??????
const example1: Metrics = {
datetime: new Date(),
activity: 12.34,
min: 12.34,
max: 12.34,
}
const example2: Metrics = {
datetime: new Date(),
avg: 12.34,
}
Here is what I tried:
type Metrics = {
datetime: Date,
[key: string]: number,
}
// ERROR on the type definition:
// Property 'datetime' of type 'Date' is not assignable to string index type 'number'
type Metrics = {
datetime: Date
} & {
[key: string]: number
}
// ERROR on the variable assignment:
// Type '{ datetime: Date; activity: number; min: number; max: number; }' is not assignable to type 'Metrics'.
// Type '{ datetime: Date; activity: number; min: number; max: number; }' is not assignable to type '{ [key: string]: number | null; }'.
// Property 'datetime' is incompatible with index signature.
// Type 'Date' is not assignable to type 'number'.
Upvotes: 5
Views: 1316
Reputation: 2082
It's a bit hacky but I found a way to do this to add a type based on your object. This allows you to export a typed object.
const example1 = {
datetime: new Date(),
activity: 12.34,
min: 12.34,
max: 12.34,
}
type AllKeys<T> = {
[Property in keyof T]: number;
};
type NewType = AllKeys<Omit<typeof example1, "datetime">> & { datetime: Date};
export const example: NewType = example1;
Upvotes: 0
Reputation: 21453
You will want something that uses Record<Exclude<K,"datetime">, number>
to map all present keys to type number but exclude the key "datetime". Since this won't necessarily be possible with a usual index type you are probably best off using a helper function that constrains the type as a generic:
type Metrics<K extends keyof any> = { datetime: Date } & Record<Exclude<K, "datetime">, number>;
function makeMetrics<T extends Metrics<keyof T>>(metrics: T): T {
return metrics;
}
const example1 = makeMetrics({
datetime: new Date(),
activity: 12.34,
min: 12.34,
max: 12.34,
});
const example2 = makeMetrics({
datetime: new Date(),
avg: 12.34,
});
This means that both examples will only allow the keys that are present when it is defined, adding extra keys later would not, in order to allow that you'd need something like "all keys except datetime
are numbers" which is not possible as far as I know.
Upvotes: 1