WHen you create literal empty object on the fly, TS forbids you to add any properties to it, because according to inference, it should be empty. I am talking about this line:
const obj = {};
Hence, in order to make it in TS way, you need to infer provided arguments:
function createObj<Key extends PropertyKey, Value>(key: Key, value: Value): Record<Key, Value>
function createObj<Key extends PropertyKey, Value>(key: Key, value: Value) {
const obj: Partial<Record<Key, Value>> = {};
obj[key] = value;
return obj;
}
const result = createObj('a', 1)
result.a // number
Key
- represents infered type of key
argument
Value
- represents infered type of value
argument
I used Partial<Record<Key, Value>>
type for obj
. For Partial
and Record
see docs.
Partial
- all values are optional
Record
- represents a hash map data structure (regular object in javascript)
As you might have noticed, result.a
infered as a number.
We can do better. Just add type Json
:
type Json =
| null
| undefined
| string
| number
| Array<Json>
| { [prop: string]: Json }
function createObj<Key extends PropertyKey, Value>(key: Key, value: Value): Record<Key, Value>
function createObj<Key extends PropertyKey, Value>(key: Key, value: Value) {
const obj: Partial<Record<Key, Value>> = {};
obj[key] = value;
return obj;
}
const result = createObj('a', 1)
result.a // 1
Now, result.a
is 1