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)
}