Index signatures
It is possible to denote obj as any, but that defeats the whole purpose of using typescript. obj = {} implies obj is an Object. Marking it as any makes no sense. To accomplish the desired consistency an interface could be defined as follows, using an index signature
interface LooseObject {
[key: string]: any
}
var obj: LooseObject = {};
OR to make it compact:
var obj: {[k: string]: any} = {};
LooseObject can accept fields with any string as key and any type as value.
obj.prop = "value";
obj.prop2 = 88;
The real elegance of this solution is that you can include typesafe fields in the interface.
interface MyType {
typesafeProp1?: number,
requiredProp1: string,
[key: string]: any
}
var obj: MyType ;
obj = { requiredProp1: "foo"}; // valid
obj = {} // error. 'requiredProp1' is missing
obj.typesafeProp1 = "bar" // error. typesafeProp1 should be a number
obj.prop = "value";
obj.prop2 = 88;
Record<Keys,Type> utility type
Update (August 2020): @transang brought up the Record<Keys,Type> utility type in comments
Record<Keys,Type>is a Utility type in typescript. It is a much cleaner alternative for key-value pairs where property-names are not known. It's worth noting thatRecord<Keys,Type>is a named alias to{[k: Keys]: Type}whereKeysandTypeare generics. IMO, this makes it worth mentioning here
For comparison,
var obj: {[k: string]: any} = {};
becomes
var obj: Record<string,any> = {}
MyType can now be defined by extending Record type
interface MyType extends Record<string,any> {
typesafeProp1?: number,
requiredProp1: string,
}
While this answers the Original question, the answer here by @GreeneCreations might give another perspective on how to approach the problem.
Answer from Akash on Stack OverflowIndex signatures
It is possible to denote obj as any, but that defeats the whole purpose of using typescript. obj = {} implies obj is an Object. Marking it as any makes no sense. To accomplish the desired consistency an interface could be defined as follows, using an index signature
interface LooseObject {
[key: string]: any
}
var obj: LooseObject = {};
OR to make it compact:
var obj: {[k: string]: any} = {};
LooseObject can accept fields with any string as key and any type as value.
obj.prop = "value";
obj.prop2 = 88;
The real elegance of this solution is that you can include typesafe fields in the interface.
interface MyType {
typesafeProp1?: number,
requiredProp1: string,
[key: string]: any
}
var obj: MyType ;
obj = { requiredProp1: "foo"}; // valid
obj = {} // error. 'requiredProp1' is missing
obj.typesafeProp1 = "bar" // error. typesafeProp1 should be a number
obj.prop = "value";
obj.prop2 = 88;
Record<Keys,Type> utility type
Update (August 2020): @transang brought up the Record<Keys,Type> utility type in comments
Record<Keys,Type>is a Utility type in typescript. It is a much cleaner alternative for key-value pairs where property-names are not known. It's worth noting thatRecord<Keys,Type>is a named alias to{[k: Keys]: Type}whereKeysandTypeare generics. IMO, this makes it worth mentioning here
For comparison,
var obj: {[k: string]: any} = {};
becomes
var obj: Record<string,any> = {}
MyType can now be defined by extending Record type
interface MyType extends Record<string,any> {
typesafeProp1?: number,
requiredProp1: string,
}
While this answers the Original question, the answer here by @GreeneCreations might give another perspective on how to approach the problem.
This solution is useful when your object has Specific Type. Like when obtaining the object to other source.
let user: User = new User();
(user as any).otherProperty = 'hello';
//user did not lose its type here.
I have an empty object x that I want to add instances of classes to by string. How can I get type enforcement for such a thing?
example:
class A {
}
class B {
}
class C {
}
const x: {[key: string]: A | B} = {};
x["a"] = new A();
x["b"] = new B();
x["c"] = new C(); // should give an errorPlayground:
https://www.typescriptlang.org/play/?ssl=12&ssc=42&pln=1&pc=1#code/MYGwhgzhAECC0G8BQBfJpIwEKNe8U0AwrmugPYB2EALtAB4BciA2gNYCmAns7QE4BLSgHMAus3gAfaFhTQAvIhQBuJEnosARGE2iF0ShwDucABQBKVRs0AjXfsMmsFq1uD3Fj4i+gB6X9AQABbkAK4gACbQwgIAbhzQYJTQHHx85HxAA
Dynamic object keys in TypeScript
Dynamically assign object property
Creating object with dynamic keys - javascript
Assign dynamic properties from constructor to class (typechecking)
You could do it like this
class Person<T> {
name: string
props: T
constructor(name: string, dynProps: T) {
this.name = name
this.props = dynProps
}
}
const p = new Person('asd', { age: 10, address: 'CA' })
const age = p.props.age // inferred type is number
const address = p.props.address // inferred type is stringPlayground Link
More on reddit.comHi everyone, please help me with this compile error:
interface Person {
id: string,
name?: string,
age?: number
}
const originalPerson: Person = {id: "123", name: "Original"}
const updatePayload: Person = {id: "123", name: "Updated"};
Object.entries(updatePayload).forEach(([key, value]) => {
originalPerson[key as keyof Person] = value;
});The last line is having this error:
Looks like `value` is of type `any`, and `originalPerson[key as keyof Person]` is of type `never`. I also observed that if I change the type of `age` from `number` to `string` then the error will go away.
Not sure how can I fix this issue. For context: the original object is a very big object with multiple nested levels stored in a reactive store, while the updatePayload object is much much smaller so I may not want to reassign the original object to a new one every time I want to make an update.
In the new ES2015 standard for JavaScript (formerly called ES6), objects can be created with computed keys: Object Initializer spec.
The syntax is:
var obj = {
[myKey]: value,
}
If applied to the OP's scenario, it would turn into:
stuff = function (thing, callback) {
var inputs = $('div.quantity > input').map(function(){
return {
[this.attr('name')]: this.attr('value'),
};
})
callback(null, inputs);
}
Note: A transpiler is still required for browser compatiblity.
Using Babel or Google's traceur, it is possible to use this syntax today.
In earlier JavaScript specifications (ES5 and below), the key in an object literal is always interpreted literally, as a string.
To use a "dynamic" key, you have to use bracket notation:
var obj = {};
obj[myKey] = value;
In your case:
stuff = function (thing, callback) {
var inputs = $('div.quantity > input').map(function(){
var key = this.attr('name')
, value = this.attr('value')
, ret = {};
ret[key] = value;
return ret;
})
callback(null, inputs);
}
You can't define an object literal with a dynamic key. Do this :
var o = {};
o[key] = value;
return o;
There's no shortcut (edit: there's one now, with ES6, see the other answer).