2

I have seen a similar question asked about this problem for javascript. However, I need the answer in typescript and I can't figure out how to do it. Convert string value to object property name

let madeObject = {};
const fieldName = 'title';
madeObject[fieldName] = 'hello';

Also, I am trying to create an interface from a string[] where each element is a string with the desired property name and value type. Use elements of an array to set the fields of a new object. Because of this, I won't know before hand what my properties are going to be, hence why I am trying to find a way to create a new interface with the given properties.

Matthew Guo
  • 25
  • 1
  • 5
  • Errors often explain what's wrong. What's your error? If it's something like `the property "title" doesn't exist on type {}`, then the type system is helping you. If you want `madeObject` to have a `title` property, you need to give it a type like `let madeObject: {title?: string} = {}`. – jcalz Jul 17 '19 at 18:33

1 Answers1

5

That's because typescript infers the type of madeObject to be {} (empty object). Just give it a more explicit type

interface MyObject {
    title:string;
}

let madeObject:Partial<MyObject> = {};
const fieldName:keyof MyObject = 'title';
madeObject[fieldName] = 'hello';

If you know that an object will have keys, but you don't know the name of the keys (maybe because they are only known at runtime), then you can use typescripts dynamic keys

interface MyObject {
    // left side is the type of the key (usually string or symbol)
    // right side is the type of the property (use "any" if you don't know)
    [key:string]: string; 
}

let madeObject:MyObject = {};
const fieldName:string = 'title';
madeObject[fieldName] = 'hello';

// Or you can make the interface Generic, if you have this situation a lot:

interface MyObjectGeneric <V = any, K = string> {
    [key:K]: V; 
}

let madeObject:MyObjectGeneric/* <string> */ = {}; // Adding <string> would narrow the return type down to string
const fieldName:string = 'title';
madeObject[fieldName] = 'hello';

Another way to solve this would be to remove the type safety all together (this is NOT recommended and makes typescript lose its purpose)

let madeObject:any = {}; // declares that madeObject could be anything
const fieldName = 'title';
madeObject[fieldName] = 'hello';

// alternatively:

let madeObject2 = {}; // Type inferred as "{}"
(madeObject2 as any)[fieldName] = 'hello'; // Removes type safety only temporarily for this statement
pascalpuetz
  • 5,238
  • 1
  • 13
  • 26
  • Are you saying the alternative way is fine or is it still not recommended – Matthew Guo Jul 17 '19 at 19:17
  • @MatthewGuo It is still not recommended. Typescript's main purpose is to document your types and find mistakes based on types. Imagine you had a typo in your `fieldName` string: `const fieldName = 'tiiiitle'`. If you used the first way, the typescript compiler will tell you that 'tiiiitle' is not a property key of `MyObject` - whereas, if you used any, it would compile and you'd only notice the error during runtime. – pascalpuetz Jul 17 '19 at 19:25
  • I get that. However, with my other problem which I added on above, I am trying to build an interface from a string[]. I don't know how to circumvent this issue because I don't have the interface to work off of to begin with. – Matthew Guo Jul 17 '19 at 19:33
  • @MatthewGuo Ah okay, so you want to dynamically add keys to an object and you only know at runtime which keys are available? If you know the possible keys at build time, then building the interface yourself is best practice. If you DON'T know them at build time but only at runtime, then you can use another alternative (I'll add that to my answer). – pascalpuetz Jul 17 '19 at 19:35
  • I really appreciate your help here. I am trying to auto generate type interfaces based on an input to a function that asks for a type from a database (i.e. if there is a type in the database called QueryInput, I want to auto create an interface for that) So while I know what I need, I can't just hard code it. – Matthew Guo Jul 17 '19 at 19:39
  • @MatthewGuo You're very welcome. I should mention though that types in typescript are only present during compile time. During run time, the interfaces will be gone. – pascalpuetz Jul 17 '19 at 19:45