I'd like to be distinguish the following function types in conditional type checks:
type SyncFn = () => void;
type AsyncFn = (data: number) => Promise<void>;
type SyncFnWithArg = (data: number) => void;
So I can then use the KeyOfType that @Titian Cernicova-Dragomir posted and get the keys within a given interface that match a given type.
I tried the following:
type SyncFn = () => void;
type AsyncFn = (data: number) => Promise<void>;
type SyncFnWithArg = (data: number) => void;
interface Foo {
a?: string;
b?: number;
c: number;
d: string;
f1?: SyncFn;
f2?: AsyncFn;
f3?: SyncFnWithArg;
}
// note: `KeyOfType` from https://stackoverflow.com/questions/49752151/typescript-keyof-returning-specific-type
type KeyOfType<T, V> = keyof { [P in keyof T as T[P] extends V? P: never]: any }
type KeyOfTypeOptionalIncluded<T, Condition> = KeyOfType<T, Condition | undefined>
let onlyStrings: KeyOfTypeOptionalIncluded<Foo, string>;
onlyStrings = 'a' // ✅ working as expected
onlyStrings = 'b' // ✅ erroring out as expected
onlyStrings = 'd' // ✅ working as expected
let onlySyncFn: KeyOfTypeOptionalIncluded<Foo, SyncFn>;
onlySyncFn = 'f1' // ✅ working as expected
onlySyncFn = 'f2' // ✅ erroring out as expected
onlySyncFn = 'f3' // ✅ erroring out as expected
let onlyAsyncFn: KeyOfTypeOptionalIncluded<Foo, AsyncFn>;
onlyAsyncFn = 'f1' // ✅ erroring out as expected
onlyAsyncFn = 'f2' // ✅ working as expected
onlyAsyncFn = 'f3' // ✅ erroring out as expected
let onlySyncFnWithArg: KeyOfTypeOptionalIncluded<Foo, SyncFnWithArg>;
onlySyncFnWithArg = 'f1' // should error out
onlySyncFnWithArg = 'f2' // should error out
onlySyncFnWithArg = 'f3' // ✅ working as expected
The problem is that onlySyncFnWithArg is being typed as "f1" | "f2" | "f3" whereas it should be "f3"....
I also noticed that if I modify AsyncFn and remove its argument then I have more problems since the type definition for onlySyncFn is now incorrect since now it's "f1" | "f2" instead of only being "f1" as it is in the first TS Playground above.
I guess that's related with how function overloading in typescript is done, but I don't really know, so that's why I'm reaching out for help.... maybe it's not related, but are we able to do such function type distinction in TS?

The problem can be addressed by changing the
KeyOfTypetype as follows:A extends BandB extends A):[A] extends [B]).Find a playground example here, and an interesting discussion here about various ways to test for type equality (each with their own caveats).