New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TS Typing issue with bindNodeCallback and readdir #5942
Comments
also I already told the type checker that its okay:
|
It appears this works better in 7.0, but not perfect. For 6.0, I recommend just casting |
Note to @cartant and @kolodny (who worked on this for v7), looking more at this, there's simply no way to perfectly type export function readdir(
path: PathLike,
options: { encoding: BufferEncoding | null; withFileTypes?: false } | BufferEncoding | undefined | null,
callback: (err: NodeJS.ErrnoException | null, files: string[]) => void,
): void;
export function readdir(path: PathLike, options: { encoding: "buffer"; withFileTypes?: false } | "buffer", callback: (err: NodeJS.ErrnoException | null, files: Buffer[]) => void): void;
export function readdir(
path: PathLike,
options: BaseEncodingOptions & { withFileTypes?: false } | BufferEncoding | undefined | null,
callback: (err: NodeJS.ErrnoException | null, files: string[] | Buffer[]) => void,
): void;
export function readdir(path: PathLike, callback: (err: NodeJS.ErrnoException | null, files: string[]) => void): void;
export function readdir(path: PathLike, options: BaseEncodingOptions & { withFileTypes: true }, callback: (err: NodeJS.ErrnoException | null, files: Dirent[]) => void): void; I've messed with it a lot, and I can't really get the types to infer properly for these given how they work, and I'm not sure TypeScript could ever support it. In fact, while trying to properly type this, I tried to see what TypeScript does with |
This is a TS limitation with the way TS only does inference on the last overload of a function. Note that if you used the last overload in this case in Also note, there's no way to tell TS which overload you want to use (like Short of converting the overload to a conditional type (please don't), there isn't a way to get this to work on the RxJS side of things 😢 |
It appears there is a way to get this to work based on what I stumbled upon today: Expand to see the full code exampleimport * as fs from 'fs';
type OverloadedArgumentsAndReturnType<T> =
T extends {
(...args: infer A1): infer R;
(...args: infer A2): infer R;
(...args: infer A3): infer R;
(...args: infer A4): infer R;
(...args: infer A5): infer R;
(...args: infer A6): infer R;
(...args: infer A7): infer R;
(...args: infer A8): infer R;
(...args: infer A9): infer R;
(...args: infer A10): infer R;
} ? [A1|A2|A3|A4|A5|A6|A7|A8|A9|A10, R] :
T extends {
(...args: infer A1): infer R;
(...args: infer A2): infer R;
(...args: infer A3): infer R;
(...args: infer A4): infer R;
(...args: infer A5): infer R;
(...args: infer A6): infer R;
(...args: infer A7): infer R;
(...args: infer A8): infer R;
(...args: infer A9): infer R;
} ? [A1|A2|A3|A4|A5|A6|A7|A8|A9, R] :
T extends {
(...args: infer A1): infer R;
(...args: infer A2): infer R;
(...args: infer A3): infer R;
(...args: infer A4): infer R;
(...args: infer A5): infer R;
(...args: infer A6): infer R;
(...args: infer A7): infer R;
(...args: infer A8): infer R;
} ? [A1|A2|A3|A4|A5|A6|A7|A8, R] :
T extends {
(...args: infer A1): infer R;
(...args: infer A2): infer R;
(...args: infer A3): infer R;
(...args: infer A4): infer R;
(...args: infer A5): infer R;
(...args: infer A6): infer R;
(...args: infer A7): infer R;
} ? [A1|A2|A3|A4|A5|A6|A7, R] :
T extends {
(...args: infer A1): infer R;
(...args: infer A2): infer R;
(...args: infer A3): infer R;
(...args: infer A4): infer R;
(...args: infer A5): infer R;
(...args: infer A6): infer R;
} ? [A1|A2|A3|A4|A5|A6, R] :
T extends {
(...args: infer A1): infer R;
(...args: infer A2): infer R;
(...args: infer A3): infer R;
(...args: infer A4): infer R;
(...args: infer A5): infer R;
} ? [A1|A2|A3|A4|A5, R] :
T extends {
(...args: infer A1): infer R;
(...args: infer A2): infer R;
(...args: infer A3): infer R;
(...args: infer A4): infer R;
} ? [A1|A2|A3|A4, R] :
T extends {
(...args: infer A1): infer R;
(...args: infer A2): infer R;
(...args: infer A3): infer R;
} ? [A1|A2|A3, R] :
T extends {
(...args: infer A1): infer R;
(...args: infer A2): infer R;
} ? [A1|A2, R] :
T extends (...args: infer A) => infer R ? [A, R] : never;
type OverloadedArguments<T> = OverloadedArgumentsAndReturnType<T>[0];
type OverloadedReturnType<T> = OverloadedArgumentsAndReturnType<T>[1];
let foo: OverloadedArgumentsAndReturnType<typeof fs.readFile>[0];
fs.readFile('test', {}, () => {})
type Head<T extends readonly unknown[]> = T[0]
type Rest<T extends readonly unknown[]> = T extends T ? ((...args: T) => any) extends (a: any, ...rest: infer R) => any ? R : never : never
type AllButLast<T extends any[]> = T extends T ? T extends [ ...infer Head, any ] ? Head : never;
let foo2: AllButLast<OverloadedArguments<typeof fs.readFile>> = {} as never;
foo2 = [''] // ok
foo2 = ['', {encoding: 'ascii'}] // ok
foo2 = ['', {encoding: 'asci'}] // error Note the last bit where we can see the overload parameter types working: let foo2: AllButLast<OverloadedArguments<typeof fs.readFile>> = {} as never;
foo2 = [''] // ok
foo2 = ['', {encoding: 'ascii'}] // ok
foo2 = ['', {encoding: 'asci'}] // error I need to spend a bit of time to incorporate this into RxJS but I don't see why we won't just use this more powerful inference for functions. |
We are not going to attempt to make any changes to the types to that the override signatures are 'mapped' to the observable type for the reasons given in this comment. The workaround it to pass an error function to |
Bug Report
Current Behavior
Type of Observable created by bindNodeCallback(readdir) is not properly advertised.
causes VSCode to issue following complaint:
Type 'Observable<unknown>' is not assignable to type 'Observable<string[]>'.
Reproduction
Paste following code into a VSCode editor.
Expected behavior
bindNodeCallback(readdir) should advertise Observable<string[]> as return type.
Environment
Additional context/Screenshots
node typings correctly advertises readdir, but bindNodeCallback somehow fails to advertise the correct type.
The text was updated successfully, but these errors were encountered: