Question: Partial does not know how many arguments are available?
lukasbash opened this issue · 2 comments
Given the following super simple snippet:
function foo(x: string) {
// some logic
return something;
}
const y = partial(x, ["bar"])
I would expect that y
is a function that takes no parameter because one is already baked in. Of course same goes for other parameters, e.g. if the function takes 3 args and I partial 2, it should come out with 1 arg after the partial.
Any information about this?
As far as I could see in the types, there is no overload for defining the parameter types as well. Is it possible to infer those?
I tried a bit but it seems it's easy to get Excessive stack depth comparing types
and tsc
crash, though it did show the correct type in VSCode.
(require TS 3.0)
// from https://github.com/Microsoft/TypeScript/pull/24897#issuecomment-400989548
type Tail<L extends any[]> = ((...x: L) => void) extends ((
h: any,
...rest: infer T
) => void)
? T
: never;
// R.partial
type Shift<T extends any[], U extends any[]> = {
0: T;
1: Shift<Tail<T>, Tail<U>>;
2: never; //=> how to throw type error?
}[U extends [] ? 0 : T[0] extends U[0] ? 1 : 2];
declare function partial<T extends any[], U extends any[], R>(
fn: (...args: T) => R,
args: U
): (...args: Shift<T, U>) => R;
// test
type ShiftTest = Shift<[1, 2, 3], [1, 2]>; //=> [3]
declare function tuple<T extends any[]>(...args: T): T;
declare function foo(x: null, y: boolean, z: number): string;
const a = partial(foo, tuple()); //=> (null, boolean, number) => string
const b = partial(foo, tuple(null)); //=> (boolean, number) => string
const c = partial(foo, tuple(null, false)); //=> (number) => string
const d = partial(foo, tuple(null, false, 0)); //=> () => string
const invalid = partial(foo, tuple(1)); //=> (...never) => string
cc @tycho01
My Playground crashes once I paste in partial
, and there are still some outstanding issues about recursive types crashing.
how to throw type error?
Maybe with some infer
voodoo, otherwise I'm not so sure we can.
It's great to see tuple manipulation has suddenly started going mainstream too -- progress! :)
The tuple
trick is new to me. It's unfortunate we need hacks for granular inference, but this is definitely an improvement over regular casts -- pretty cool!
It'd be cool if we could otherwise constrain U
input to tuples too though. I fiddled for a bit along the lines of declare function tuplesOnly<T>(x: { length: number extends infer T ? T : never });
, but no success. I'm really bad at this infer
voodoo magic, so that was to be expected.
Another attempt:
type ActualNumber<T, U = number extends T ? never : T> = U;
let a: ActualNumber<1>; // 1
let b: ActualNumber<number>; // never
I tried making a tuple type based on a length
involving ActualNumber
, but no luck so far.
Cheap man's version 🤡:
type SomeNatural = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
type Tpl = any[] & { length: SomeNatural };
Alas though, this wasn't as useful as I hoped: it didn't provide free casts as a solution to tuple()
.
declare function foo(x: Tpl);
foo([1]); // error: number[] not assignable to Tpl
In this particular case though, couldn't we just change partial
's U extends any[]
to U extends T
?