micro-dash icon indicating copy to clipboard operation
micro-dash copied to clipboard

invoke: Throw error if the invoked function name matches no function

Open lpepin-sama opened this issue 5 years ago • 1 comments

If using invoke(params, 'somefunction') somewhere in the code and then we later rename somefunction to someotherfunction, an error should be thrown to let the developer know that invoke is being called with the wrong function name.

A use case for this is when a function is renamed through the IDE if 'search in strings' when refactoring is disabled.

lpepin-sama avatar Jul 02 '20 15:07 lpepin-sama

I'm having trouble finding a solution that gives this error and still allows passing a string[] for the path (which should be supported).

Here's a simplified (believe it or not) definition one can play with to try finding a solution:

// utility types
type Key = keyof any;
type Nil = null | undefined;
type Fn = (...args: any[]) => any;
type Primitive = boolean | number | string;
type Existent = Primitive | object;
type NonUndefined<A> = A extends undefined ? never : A;

// wild types used within invoke
type Obj1<K1 extends Key, V> = { [key in K1]?: V };
type Path1<K1 extends Key, T extends Obj1<K1, any> | Nil> = T extends Existent
  ? T[K1]
  : NonNullable<T>[K1] | undefined;
type DefinedPath1<K1 extends Key, T extends Obj1<K1, any> | Nil> = NonUndefined<
  NonNullable<T>[K1]
>;

// invoke typings
declare function invoke<K1 extends Key, T extends Obj1<K1, Fn> | Nil>(
  object: T,
  path: [K1],
  ...args: Parameters<DefinedPath1<K1, T>>
): Path1<K1, T> extends DefinedPath1<K1, T>
  ? ReturnType<DefinedPath1<K1, T>>
  : ReturnType<DefinedPath1<K1, T>> | undefined;

declare function invoke(
  object: object | Nil,
  path: Key[],
  ...args: any[]
): unknown;

////////////////////////////////////////////// these should all still work

// $ExpectType number
invoke({ a: () => 1 }, ['a']);
// $ExpectType boolean
invoke({ a: (a: boolean) => a }, ['a'], true);
// $ExpectType string | undefined
invoke({} as { a?: () => string }, ['a']);
// $ExpectType string | undefined
invoke({} as { a: () => string } | Nil, ['a']);

const pathN = ['a'] as string[];
// $ExpectType unknown
invoke({ a: () => 1 }, pathN);

///////////////////////////////////////// and we want this to give an error
// $ExpectError
invoke({ a: () => 1 }, ['b']);

ersimont avatar Jul 04 '20 17:07 ersimont