I have two typescript types that I would like to combine into one generic type:
type WordTimestamps = {
timestamps: {start: number, end: number},
word: string
}
type SentenceTimestamps = {
timestamps: {start: number, end: number},
sentence: string
}
The only difference between them is the second key, so I want to come up with a single generic type which I imagine should be called as something like Timestamps<'word'>
for the former and Timestamps<'sentence'>
for the latter.
I can't seem to figure out how to do this. I've only come up with the code below, which doesn't do it.
type Timestamps<T> = {
timestamps: { start: number; end: number };
[key: T]: string;
};
CodePudding user response:
Maybe a combination using Pick and Record might be suitable :
type TimestampBase = { timestamps: {start: number, end: number} };
type TimestampKeys = 'word' | 'sentence';
type Timestamp<T extends TimestampKeys> = TimestampBase & Pick<Record<T, string>, T>;
const word: Timestamp<'word'> = {
timestamps: { start: 0, end: 0 },
word: 'word'
};
const sentence: Timestamp<'sentence'> = {
timestamps: { start: 0, end: 0 },
sentence: 'sentence'
};
CodePudding user response:
You can use distributive-conditional-types:
type Keys = 'word' | 'sentence';
type Timestamp = {
timestamps: { start: number, end: number }
}
type Timestamps<T> = T extends string ? Record<T, string> & Timestamp : never
// (Record<"word", string> & Timestamp) | (Record<"sentence", string> & Timestamp)
type WordTimestamps = Timestamps<Keys>
You can add any allowed property name to Keys
. It will be automatically distributed.
T extends string ?
- makes sure that union type will be distributet over Record<T, string>