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://mcmap.net/q/387187/-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?