我有这样的代码:

const tokens = [
  {
    re: /^(#.*)$/,
    parse: function(line: string) {
      const style = styles.header;
      return {
        content: line,
        style,
      };
    }
  },
  {
    re: /^(__)([^_]+)(__)/,
    parse: function(_:string, g1:string, text:string, g2:string) {
       return {
         content: text
       };
    }
  }
];

const createChunks = (text: string) => {
  return text.split('\n').map((line: string) => {
    const chunk_parser = tokens.find(({re}) => re.test(line));
    if (chunk_parser) {
      const { parse, re } = chunk_parser;
      const m = line.match(re);
      if (m) {
        return parse(...m);
      }
    }
    return {
      content: line
    };
  });
}

问题是我不能将字符串::Match的结果转换为数组,即使它是一个类似于数组的对象.NodeJS甚至在控制台中将其显示为array.我可以使用扩散运算符或Array.From将匹配结果隐藏为数组,但TypeScrip不允许这样做,并抛出以下错误:

扩散参数必须具有元组类型或传递给REST参数.

使用跨页时,以及:

"字符串[]"类型的参数不能赋给""字符串""类型的参数""

使用Array.From时.

这是NodeJS的输出:

> '# foo'.match(/^(#.*)$/)
[ '# foo', '# foo', index: 0, input: '# foo', groups: undefined ]
> [...'# foo'.match(/^(#.*)$/)]
[ '# foo', '# foo' ]

推荐答案

Typescript 中RegExp's match() method的返回类型为RegExpMatchArray | null.definition of RegExpMatchArray看起来像是

interface RegExpMatchArray extends Array<string> {
  0: string;
  index?: number;
  input?: string;
}

所以它是string[]的一个子类型,有一些额外的属性.重要的是,已知RegExpMatchArray在索引0处具有已定义的string元素;也就是说,数组的第一个元素不能是未定义的.

但不幸的是,当你在打字脚本中输入spreadRegExpMatchArray时,它会将其视为string[],并且忘记了0存在的附加信息.这是您问题的主要来源.

我想说的是,这是一个设计限制,尽管我在搜索giHub问题时并没有看到有人抱怨散布一个RegExpMatchArray,所以我没有一个权威的分类来源.但无论如何,你都需要解决这个问题.


如果你想使用RegExpMatchArray英寸的Typescript 并让它正常工作,你需要切换到使用open-ended tuple type [string, ...string[]].但是TypeScrip不认为RegExpMatchArray可以分配给该类型(本质上与它不可传播的原因相同),所以您需要使用type assertion.

因此,我可能会使用这样的方法:

interface Token {
  re: RegExp;
  parse(
    line: string,
    ...matches: string[]
  ): { content: string, style?: string }
}

const tokens: Token[] = { ⋯ }

在这里,我让编译器知道,可以使用任何正数的string个参数来调用这parse()个方法.如果您不这样做,那么编译器将看到您的parse()个单独的实现,如果您将任意长度的数组传递给只接受两个或三个输入的对象,编译器会发出警告.

然后,我们可以使用必需的类型断言:

return parse(...(m as [string, ...string[]]));

如果您不想使用类型断言并放松类型安全,则可以使用0键手动索引到RegExpMatchArray,然后对其余部分进行切片:

return parse(m[0], ...m.slice(1));

这有一个运行时效果,但更"安全",因为编译器可以判断m实际上有一个0索引.

无论哪种方式,你都可以继续下go .

Playground link to code

Typescript相关问答推荐

如何将http上下文附加到angular中翻译模块发送的请求

ReturnType此索引方法与点表示法之间的差异

如何解决类型T不能用于索引类型{ A:typeof A; B:typeof B;. }'

被推断为原始类型的交集的扩充类型的交集

我可以以这样一种方式键入对象,只允许它的键作为它的值吗?

如何在NX工作区项目.json中设置类似angular.json的两个项目构建配置?

在排版修饰器中推断方法响应类型

重载函数的T helper参数

TypeScrip:强制使用动态密钥

基于泛型的条件接口键

将接口映射到交叉口类型

使用或属性编写无限嵌套的接口

VITEST警告:当前的测试运行器不支持After Each/teardown挂钩

错误TS7030:并非所有代码路径都返回值.";由tsfig.json中的";Strong";:False引起

为什么受歧视的unions 在一种情况下运作良好,但在另一种非常类似的情况下却不起作用?

基于区分的联合键的回调参数缩小

为什么类方法参数可以比接口参数窄

两个接口的TypeScript并集,其中一个是可选的

如何从联合类型推断函数参数?

Angular另一个组件的nativeelement未定义