Skip to content
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

Question: Partial does not know how many arguments are available? #412

Open
lukasbash opened this issue Aug 17, 2018 · 2 comments
Open

Question: Partial does not know how many arguments are available? #412

lukasbash opened this issue Aug 17, 2018 · 2 comments

Comments

@lukasbash
Copy link

lukasbash commented Aug 17, 2018

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?

@ikatyang
Copy link
Member

ikatyang commented Aug 17, 2018

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

@KiaraGrouwstra
Copy link
Member

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants