There are lots of questions about this general topic.
Following @Aluan Haddad's suggestion, you can use mapped types. I've changed the key to be optional since you give {}
as an acceptable return value. Also, I don't believe your if
statement is necessary since the type is already checked when value
is passed to the function:
function stringThingIn <T extends string>(value: string | undefined, key: T): { [k in T]?: string | undefined } {
return { [key]: value } as { [k in T]?: string | undefined };
}
However, having to repeat the type twice and cast the result is pretty terrible. You can define the type externally to reuse it, and then create the object before assigning the key:
type stringType<T extends string> = {
[k in T]?: string | undefined
}
function stringThing <T extends string>(value: string | undefined, key: T): stringType<T> {
let result: stringType<T> = { };
result[key] = value;
return result;
}
Or, to simplify things a bit, you can use a Record
:
function stringRecord <T extends string>(value: string | undefined, key: T) {
let result: Partial<Record<T, typeof value>> = {};
result[key] = value;
return result;
}
If someone has a suggestion for how to avoid creating the temporary result
object, I am all ears. I could not get it to work otherwise (without casting).