See the following code:
function createObj(key: string, value:unknown) {
const obj = {};
obj[key] = value;
return obj;
}
gives error:
TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. No index signature with a parameter of type 'string' was found on type '{}'.
I know I could write it as
const obj = {} as Record<string, unknown>;
but I wonder if I could initialize the object in one statement, like
const obj = {
key: value
};
which does not work because key is a string literal here and not the value of variable key.
CodePudding user response:
One can use computed property names (referenced by another answer) as follows:
function createObj(key: string, value: unknown) {
return {
[key]: value,
};
}
CodePudding user response:
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