Last active
February 10, 2020 00:37
-
-
Save rob3c/6cbaad2bd8314a4d2a8b578ceac1058b to your computer and use it in GitHub Desktop.
Clarifying intersection vs union typescript expectations in function parameters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const myFnMap = { | |
fnA: ({pa}: {pa: string}) => `fnA(${pa})`, | |
fnB: ({pb}: {pb: string}) => `fnB(${pb})`, | |
}; | |
type MyFnMap = typeof myFnMap; | |
// as expected: 'fnA' | 'fnB' | |
type MyFnKey = keyof MyFnMap; | |
// as expected: (({ pa }: { pa: string; }) => string) | (({ pb }: { pb: string; }) => string) | |
type MyFn = MyFnMap[MyFnKey]; | |
// as expected: { pa: string; } | { pb: string; } | |
type MyFnParam = Parameters<MyFn>[0]; | |
function callMappedFn< | |
TKey extends keyof MyFnMap, | |
>( | |
key: TKey, | |
arg: Parameters<MyFnMap[TKey]>[0] | |
): string { | |
// Get the function for the specific key and let's see what happens... | |
const fn = myFnMap[key]; | |
// Surprise! (maybe) | |
// `fn` expects the intersection { pa: string; } & { pb: string; } | |
// instead of the union { pa: string; } | { pb: string; } | |
// that one might expect (or at least hope for when writing this lol). | |
// | |
// So the specific `arg` for the specific `key` doesn't seem to match | |
// the params in the expected way, even though it seems to be constrained | |
// by the typing. It's an illusion, though: typescript is correct - at | |
// least according to its current capabilities - if it wants every call | |
// to succeed without further checking on our part. | |
// | |
// `result` is still `string` as expected, even though `args` gets squiggles. | |
const result = fn(arg); | |
return result; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment