I am new to TypeScript, and have tried various ways to type this, but running into problems with index signatures. What should the interface look like?
interface MyConfig {
...
}
// someVar can be any string
let someVar = "dynamicKey";
// the structure of the object cannot change
const config: MyConfig = {
myObj: {
[someVar]: {
firstProp: 'some text',
secondProp: 'some text',
},
thirdProp: 'some text',
},
};
If you know the exact value or values for someVar
variable, you can have a strict interface like:
interface MyConfig {
myObj: {
SomeKey: {
firstProp: string
secondProp: string
},
thirdProp: string
}
}
Then you can use:
const someVar = "SomeKey";
const config: MyConfig = {
myObj: {
[someVar]: {
firstProp: 'some text',
secondProp: 'some text',
},
thirdProp: 'some text',
},
};
But if you wish that someVar
would be dynamic, it's a bit tricky. For that I would recommend you moving the dynamic part to a separate block, so you could use:
interface MyConfig {
myObj: {
dynamic: {
[key: string]: {
firstProp: string
secondProp: string
}
},
thirdProp: string
}
}
const someVar = "SomeKey";
const config: MyConfig = {
myObj: {
dynamic: {
[someVar]: {
firstProp: 'some text',
secondProp: 'some text',
},
},
thirdProp: 'some text',
},
};
And finally, if you have dynamic someVar
and can't change the data structure. you can use following:
interface MyConfig {
myObj: ({
[key: string]: {
firstProp: string
secondProp: string
} | string
} & {
thirdProp: string
})
}
const someVar: string = "SomeKey";
const config: MyConfig = {
myObj: {
[someVar]: {
firstProp: 'some text',
secondProp: 'some text',
},
thirdProp: 'some text',
},
};
// String
console.log(config.myObj.thirdProp.trim())
// Error, union string | object
console.log(config.myObj.abc.firstProp)
if (typeof config.myObj.abc === 'object') {
// string
console.log(config.myObj.thirdProp.trim())
// string
console.log(config.myObj.abc.firstProp.trim())
}
In this example, we use a typescript index signature + we specify known properties. You can also notice a strange thing - the index signature has union object | string
. This is because of typescript limitation:
As soon as you have a string index signature, all explicit members must also conform to that index signature. This is to provide safety so that any string access gives the same result.
Reference: How to combine declared interface properties with custom Index Signature