Supposed I have a type like this:
type TInfoGeneric = {
valueType: TType,
value: T
Yeah, there's no convenient and type-safe solution for you here. I've opened an issue about this but I fully expect the answer will be "it's too much work for not enough benefit to address this".
I see two main ways forward. One is to just use a type assertion, since you legitimately know more than the compiler does here. It could be like this:
function handleInfo(info: TInfo) {
// assert your way out. Not type safe but convenient!
(handlers[info.valueType] as (x: number | string)=>any)(info.value);
}
Now there's no error. It's not type safe. But it's convenient and doesn't change the emitted JavaScript.
Or you could try to walk the compiler through the cases and prove to it that all is fine. This is complex, brittle, and has runtime effects:
const typeGuards: {
[P in keyof TInfoTypeMap]: (x: TInfoTypeMap[keyof TInfoTypeMap])=>x is TInfoTypeMap[P];
} = {
num: (x:any): x is number => typeof x === "number",
str: (x:any): x is string => typeof x === "string"
}
function narrowTInfo<K extends keyof TAllPossibleTInfoMap>(
x: TInfo, v: K): x is TAllPossibleTInfoMap[K] {
return typeGuards[v](x.value);
}
function handleInfo(info: TInfo) {
if (narrowTInfo(info, "num")) {
handlers[info.valueType](info.value); // okay
} else {
handlers[info.valueType](info.value); // okay
}
}
That works but is obnoxious. So I'd recommend an assertion.
Hope that helps; good luck!