函数的参数指定Typescript中的几个函数类型

函数的参数指定Typescript中的几个函数类型,typescript,Typescript,这是我的代码,我不知道怎么写!我觉得非常复杂!!请帮帮我,谢谢 interface IMethods { aa(): number; bb(): boolean; cc(): string; } const methods: IMethods = { aa: (): number => { return 0; }, bb: (): boolean => { return false; }, cc: (): string =>

这是我的代码,我不知道怎么写!我觉得非常复杂!!请帮帮我,谢谢

 interface IMethods {
  aa(): number;
  bb(): boolean;
  cc(): string;
 }

const methods: IMethods = {
  aa: (): number => {
    return 0;
  },
  bb: (): boolean => {
    return false;
  },
  cc: (): string => {
    return '';
  },
};

// what type??
function Demo(func: ???) {
  func();
}

Demo(methods.aa); // expect true
Demo(function other() {}); // expect error!!!!
我想了一个办法,像这样

function Demo(func: IMethods[keyof IMethods]) {
  func();
}

我不知道有没有更好的办法

听起来你想把方法中的某些函数视为特殊函数,让它们的类型表明它们不仅仅是函数,Typescript允许我们这样做。您想要什么的基本思想是以Haskell中的关键字newtype命名。Typescript为我们提供了几种实现这种模式的方法,我特别喜欢使用

首先,我们需要一个不可能被人意外实现的类型。如果我们制作了一个界面,那么无论我们在里面放了什么,用户仍然有可能意外地满足它。因此,我们将创建一个具有私有成员的类,这将强制类型为。实际上,这意味着只有类的实际实例被视为类型的成员,而不是碰巧具有相同形状的其他对象

class NominalClass {
  private _tag: object;
}
现在我们要对类型系统撒谎,以得到我们想要的保证。类型=>T太笼统了;它将允许任何功能,包括您想要禁止的功能。所以我们要做一个新的类型,有效地说我基本上是一个函数,但我很特别。在Haskell或Scala中,我们可以将函数包装为一个新类型,但Typescript可以做得更好:交叉类型

type FromIMethods<T> = NominalClass & (() => T);
就像我说的,它们仍然是函数,所以我们仍然可以调用它们。我们只是给它们增加了一点结构。现在我们对类型系统撒谎。我们说我有办法把一个普通函数变成一个FromIMethods,这当然是不可能的,但是Typescript不在乎

function toIMethod<T>(mthd: (() => T)): FromIMethods<T> {
  return mthd as FromIMethods<T>;
}
我们编写了一个演示代码,以获取FromIMethods并返回一个T

现在,用户不可能意外地将普通函数传递给Demo;它们必须传递来自方法的函数。当然,恶意用户总是有可能通过强制转换来规避您的类型安全性

Demo((function() {}) as FromIMethods<void>)

但是对于任何类型和函数,在Typescript中都是如此,所以不值得担心。

ohhh,谢谢!!!
const methods: IMethods = {
  aa: toIMethod((): number => {
    return 0;
  }),
  bb: toIMethod((): boolean => {
    return false;
  }),
  cc: toIMethod((): string => {
    return '';
  }),
};
function Demo<T>(func: FromIMethods<T>): T {
  return func();
}
Demo(methods.aa) // True
Demo(function() {}) // Error
Demo((function() {}) as FromIMethods<void>)