Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/424.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 将类限制为仅包含具有特定签名的函数_Javascript_Typescript - Fatal编程技术网

Javascript 将类限制为仅包含具有特定签名的函数

Javascript 将类限制为仅包含具有特定签名的函数,javascript,typescript,Javascript,Typescript,在我的应用程序中,我有几个用于创建XML字符串的类。 每个类都有几个方法,这些方法接受一些参数并返回一个字符串。我想指定此限制,以便不能添加具有不同签名或其他类成员的方法。为此,我取得了如下成就: interface IRequestParser { [funcName: string]: (...args: any[]) => string; } 以及一个类的示例: class myParser implements IRequestParser { [funcName: st

在我的应用程序中,我有几个用于创建XML字符串的类。 每个类都有几个方法,这些方法接受一些参数并返回一个字符串。我想指定此限制,以便不能添加具有不同签名或其他类成员的方法。为此,我取得了如下成就:

interface IRequestParser {
  [funcName: string]: (...args: any[]) => string;
}
以及一个类的示例:

class myParser implements IRequestParser {
  [funcName: string]: (...args: any[]) => string;

  func1(a) {
    return '';
  }
}
这使我无法添加不返回字符串的函数或任何其他非方法成员,因此在
myParser
中不允许使用这些函数:

  a: string; // not allowed
  b() { // not allowed
    return 5;
  }
但是,这样做的效果是,我可以从
myParser
的实例调用任何函数名,而无需发出警报:

const a = new myParser();
console.log(a.func1('a'));
console.log(a.func2(4, 5, ['s', 'b']));
func1
的调用是有意义的,如果我没有为它的参数
a
提供一个值,我也会得到一个错误。但是,我也可以调用不存在的函数
func2
和任何其他名称


有没有一种方法既可以限制类成员的类型,又可以避免使用任何名称调用任何函数的情况?

您使用的接口允许通过任何字符串对类进行索引。我们不能用一个接口来表达您想要的约束(至少我想不出有什么办法,也许其他人有想法)

您可以使用函数约束类,使其仅具有具有签名的函数,同时保留类具有的实际属性:

type ParserFn = (...args: any[]) => string;
function createRequestParserClass<
  T extends new (...a: any[]) => Record<keyof InstanceType<T>, ParserFn>>(ctor: T) {
  return ctor
}
const myParser = createRequestParserClass(class {
  // a: string; // not allowed
  // b() { // not allowed
  //   return 5;
  // }

  func1(a: string) {
    return '';
  }
});

您也可以这样做:

class MyParser implements Record<keyof MyParser, (...args: any[]) => string> {

  // okay
  func1(a: any) {
    return '';
  }

  // error: string is not assignable to (...args: any[]) => string
  a: string; 

  // error: number is not assignable to string
  b() { 
    return 5;
  }
}

const myParser = new MyParser();
myParser.func1("okay"); // works
myParser.funcNope("huh"); // error, no property funcNope
类MyParser实现记录字符串>{
//好的
职能1(a:任何){
返回“”;
}
//错误:字符串不能分配给(…args:any[])=>字符串
a:弦;
//错误:数字不能分配给字符串
b(){
返回5;
}
}
const myParser=new myParser();
myParser.func1(“好的”);//作品
myParser.funcNope(“huh”);//错误,没有属性funcNope
允许实现具体的映射类型(如
Record
),有时还可以使用循环引用(通常可以通过
keyof
引用键)


希望有帮助;祝你好运

我将对此进行测试。如果我想在某个地方定义类,并在其他地方创建实例,那么我可以在文件中定义内部类,然后调用
createRequestParserClass
?也许可以将构造函数设置为私有,并将此函数添加到每个类中,以防止创建原始类?@RanLottem您可以像使用任何其他类一样使用const
myParser
。与类型
myParser
(我在原始答案之后添加)结合使用,这两个函数应该可以像常规函数定义一样工作。如果您想在另一个文件中使用
myParser
,请同时导出这两个文件,并且它应该可以工作。在调用
createRequestParserClass
时,尝试添加错误类型的类成员似乎会导致错误,而不是内部类的定义(这正是我尝试的“接口扩展”方法所需要的). 不过,我还是从这个解决方案中学到了很多,谢谢。@RanLottem是的,错误将在函数调用中报告,而不是在类本身中报告。我个人认为这没什么大不了的,一个错误就是一个错误,但这取决于你是否让这个解决方案对你不可用。@RanLottem昨晚没有看到jcalz的答案,他肯定更好:-)这看起来更直接,给出了更明确的错误信息。
记录
类型是我缺少的。我接受这一点。我对自己没有在
implements
子句中使用
keyof
感到有点不安。您可以这样做是有道理的,因为在检查类之后才检查实现,所以应该知道键。很好的回答:)就个人而言,我仍然对如何使用自己的
keyof
定义类型感到困惑,通常情况下,您无法使用自身定义类型,从而使其具有递归性。我注意到,在继承自
MyParser
的类中,限制被取消了,有没有办法防止这种情况发生?不,它不会向下传播。如果确实需要,您可能希望返回到索引签名,如
[whowknows:string]:undefined |((…args:any[])=>string)
。这确实存在一个问题,即
myParser.funcNope
本身不会是一个错误,但至少它的类型包括
未定义的
(假设您使用
--stricnullchecks
,您确实应该这样做),因此如果尝试调用
myParser.funcNope()
,您将得到一个错误。
class MyParser implements Record<keyof MyParser, (...args: any[]) => string> {

  // okay
  func1(a: any) {
    return '';
  }

  // error: string is not assignable to (...args: any[]) => string
  a: string; 

  // error: number is not assignable to string
  b() { 
    return 5;
  }
}

const myParser = new MyParser();
myParser.func1("okay"); // works
myParser.funcNope("huh"); // error, no property funcNope