Reputation: 720
I keep getting the below error from this line of code: oldUniforms[key] = tempUniforms[key];
. I don't understand why this doesn't work as I'm just creating a deep copy of an object of the same type.
Error:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'UpdatedUniformsType'.
No index signature with a parameter of type 'string' was found on type 'UpdatedUniformsType'.ts(7053)
Code:
type UpdatedUniformsType = {
u_BlockDia?: number;
u_CamPos?: [number, number];
};
const oldUniforms: UpdatedUniformsType = {
u_BlockDia: 16,
u_CamPos: [0, 0],
};
function setOldUniforms(updatedUniforms: UpdatedUniformsType) {
// Deep copy of updatedUniforms
const tempUniforms: UpdatedUniformsType = JSON.parse(JSON.stringify(updatedUniforms));
// Update oldUniforms using the deep copy
Object.keys(tempUniforms).forEach((key) => {
oldUniforms[key] = tempUniforms[key];
});
}
Upvotes: 0
Views: 217
Reputation: 330266
The compiler does not know that Object.keys(tempUniforms)
will produce only the expected keys. Object type in TypeScript are open/extendible and not closed/exact. If I have an object of type UpdatedUniformsType
I can talk meaningfully about what's happening at the u_BlockDia
and u_CamPos
keys, but I have no idea if it will have additional properties or not. So Object.keys(obj)
returns a string[]
in TypeScript, and not an Array<keyof typeof obj>
. See this question and its answer for more information.
If you're sure that there won't be extra keys (or if you don't care what happens when there are extra keys), then you can use a type assertion to tell the compiler Object.keys(tempUniforms)
will return Array<keyof UpdatedUniformsType>
:
(Object.keys(tempUniforms) as Array<keyof UpdatedUniformsType>)
.forEach(<K extends keyof UpdatedUniformsType>(key: K) => {
oldUniforms[key] = tempUniforms[key];
});
I also had to make the forEach()
callback a generic function so that the assignment oldUniforms[key] = tempUniforms[key]
is seen by the compiler as assigning UpdatedUniformsType[K]
to itself. If you don't do that, the compiler doesn't realize that the assignment is safe, due to a soundness improvement introduced in TS3.5. See this question and its answer for more information.
Upvotes: 1