Edit:
This is my improved solution
// This is an object as const so DataUuid is a string union
type DataUuid = keyof typeof peripheralsValueUuidNameMap
// And I used it here as well because they are all the same strings
type ServCharMap = {
[key in DataUuid]: ServChar
}
if (characteristic.uuid in servCharMap) {
// So now we only have the external data as a forced type.
// Still surprised this is not inferred.
const dataUuid = characteristic.uuid as DataUuid
const charData = servCharMap[dataUuid]
if (charData.bytes === 2) {
// We can now lose this `in` check
const name = peripheralsValueUuidNameMap[dataUuid]
...
}
}
See below for my reasoning
Yes I agree this is strange. I have the following code:
let name = ''
if (characteristic.uuid in peripheralsValueUuidNameMap) {
const uuid =
characteristic.uuid as keyof typeof peripheralsValueUuidNameMap
name = peripheralsValueUuidNameMap[uuid]
}
I woud assume ts infers the as keyof typeof peripheralsValueUuidNameMap
but it only stops complaining if I force it in this way.
I KNOW characteristic.uuid
is a key of peripheralsValueUuidNameMap
because the in
check succeeded.
peripheralsValueUuidNameMap
is a const type so everything about it is known.
The problem is, all keys are const
strings so can not be indexed by string
type. Strangely, even if the in
check has completed. I would assume the type of characteristic.uuid
to become a union of all key strings of peripheralsValueUuidNameMap
and that is exactly what as keyof typeof
does.
In this case it does work:
if (characteristic.uuid in servCharMap) {
const charData = servCharMap[characteristic.uuid]
}
Because servCharMap has type
type ServCharMap = {
[key: string]: ServChar
}
But here we don't even need the in
check, const charData = servCharMap[characteristic.uuid]
this code alone does not give a type error because we are indexing servCharMap
with a string type. This means for all TS cares charData
can evaluate to undefined.
characteristic
can not be typed as a const
type because it comes from an external data source.
So in conclusion, both situations have flaws and hide footguns.
a
is a string literal type, isn't it? – Splay