There are two ways to solve your problem depending on your usecase. If you just want to set any string as a value to any particular key, you don't need to use generics:
function setProperty(obj: Record<string, string>, key: string) {
obj[key] = "hello";
}
However if your object has specific keys and specific values you can use generics like this so the compiler type checks your arguments:
function setProperty<T extends Record<string, string>, K extends keyof T, V extends T[K]>(obj: T, key: K, value: V) {
obj[key] = value
}
type ObjectValue = 'foo' | 'bar'
type A = {
foo: ObjectValue,
baz: 'baz'
}
const a: A = {
foo: 'foo',
baz: 'baz'
}
setProperty(a, 'foo', 'bar') // works
setProperty(a, 'foo', 'baz') // type error
This also has a nice benefit of InteliSense sugsestions.
EDIT:
Since OP wanted just to type check the key and set an arbitrary string, this solution should be better:
function setProperty<K extends string>(obj: Record<K, string>, key: K) {
obj[key] = "hello";
}