Home > Blockchain >  Intersection of Generic String Literals
Intersection of Generic String Literals

Time:08-24

I have a large object describing different features. For each feature, there may be other fields providing more details, e.g., comments. This may look similar like this:

type Object = {
  a: Feature,
  aComment: string,
  b: Feature
}

Now, I want to make a function which does something with the comments. What I came up with is this:

type Comment<K extends string> = `${K}Comment`;

type RequiredShape<K extends string> = {
  [Key in K]: Feature;
} & {
  [Key in Comment<K>]: string
}

function doSomethingWithComment<K extends string>(
  obj: RequiredShape<K>,
  key: K,
) {
  // no issues here, I can use this as a Feature
  const feature = obj[key];

  const commentKey = `${key}Comment` as Comment<K>;
  const comment = obj[commentKey];

  // now here comment is not treated as string, this won't work
  doSomethingWithLength(comment.length);
}

I want it to only be possible to pass "valid" keys into this function, so keys for which a comment exists in the object. I believe my issue lies somewhere in the type intersection, but don't quite get what's going on there.

CodePudding user response:

Typescript is a bit iffy on string template types as well as using them as indexors. Instead cast using as keyof object. Then also assert the comment as as string.

function doSomethingWithComment<K extends string>(
  obj: RequiredShape<K>,
  key: K,
) {
  // no issues here, I can use this as a Feature
  const feature = obj[key];

  const commentKey = `${key}Comment` as keyof RequiredShape<K>;
  const comment = obj[commentKey] as string;

  doSomethingWithLength(comment.length)
}

TS Playground Link

  • Related