Home > front end >  Generic type to dynamically set key in an object
Generic type to dynamically set key in an object

Time:10-24

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>

Playground

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>

  • Related