在泛型函数中按名称调用方法

Call method by name inside generic function

我想概括这里描述的情况:

所以我将有一个类似于下面的函数 (genericFunction),其中我还不知道 obj 类型,但我想确保obj[key] 只能是特定类型。

/// 
type Identical<T, TTest, TTrue, TFalse> = (<U extends T>(
  o: U
) => void) extends <U extends TTest>(o: U) => void
  ? TTrue
  : TFalse;

type KeyWithValueOfType<THost, TValueType> = {
  [K in keyof THost]: Identical<THost[K], TValueType, K, never>;
  // [K in keyof THost]: THost[K] extends TValueType ? K : never;
}[keyof THost];

function genericFunction<T>(
  obj: T,
  methodName: KeyWithValueOfType<T, () => void>
): void {
  const method = obj[methodName];
  // How can I guarantee that method is callable?
  // Or that it is the type that I restricted at KeyWithValueOfType <THost, TValueType>
  
  method(); // This expression is not callable.
  //   Type 'unknown' has no call signatures.
}

type TTypeMethod = KeyWithValueOfType<IType, () => void>; // = "function" | "method"
 
genericFunction({} as IType, 'f'); // ok
genericFunction({} as IType, 'm'); // ok
genericFunction({} as IType, 'p'); // ok

playground

现在您的 genericFunction 取决于对象的类型 T。我们可以翻转它,让它依赖于密钥的类型。

我们使用一个辅助实用程序类型来定义一个对象,该对象的所有可分配给 Key 的键都有一个可分配给 Value.

的值
export type HasProperty<Key extends keyof any, Value> = {
  [K in Key]: Value;
}

现在我们让 genericFunction 依赖于一个键 K extends keyof anymethodNameK 类型,对象是一个对象,每个 K 键都有一个无参数 void 函数。

function genericFunction<K extends keyof any>(
  obj: HasProperty<K, () => void>,
  methodName: K
): void {
  const method = obj[methodName];
  method();
}

这按预期工作,如果对象类型没有 methodName 中的 属性 函数,则会给我们一个错误。

genericFunction({} as IType, 'f'); // ok
genericFunction({} as IType, 'm'); // ok
genericFunction({} as IType, 'p'); // error

Playground Link