I'm trying to access object[property]
, and TypeScript is throwing the element implicitly has any type
error.
const getValue = (key: string) => {
const object = {
property0: 14
property1: -3
}
if (!(key in object)) {
throw new Error(`Invalid key: ${key}`)
}
return object[key]
}
If we don't know whether property in object
is true, we'd have to provide TypeScript with the index signature ourselves. That is, TypeScript should throw an error if we removed the if(!(key in object))
condition from that function, until we manually note the index signature of object
.
But it seems like, given we know at compile-time that key
is in object
when we make it to the return statement, TypeScript should throw no such error for this function, and should instead infer the return type of getValue
to be number
.
I can resolve the issue by manually noting the index signature of object
:
interface ObjectWithOnlyNumberProperties {
[key: string]: number
}
const getValue = (key: string) => {
const object: ObjectWithOnlyNumberProperties = {
property0: 14
property1: -3
}
if (!(key in object)) {
throw new Error(`Invalid key: ${key}`)
}
return object[key]
}
But it seems like I shouldn't have to, and the type of object[key]
should be inferable at compile-time to typeof property0 | typeof property1
since we know that key in object
is true.
Copying Romain Laurent's comment, which answers the question perfectly!
At compile time, TypeScript is dealing with types, not actual objects. By default,
{ property0: 14, property1: -3 }
is typed as{ property0: number, property1: number }
. A type in TypeScript is a minimal contract accordance, so as far as TypeScript knows, the{ property0: number, property1: number }
type could refer to an actual object like{ property0: 14, property1: -3, property2: "string" }
. Obviously, we know in the code that it won't, but TypeScript doesn't know that. And as the above case indicates,object[property]
is of typeany
, sinceproperty2
could be of any type, not juststring
.
Update: as per geoffrey's comment, if you're using target library es2022
or later, you should also update the above code to use Object.hasOwn(object, property)
instead of property in object
, to protect against prototype pollution.