【问题标题】:TS2488: Type 'string | null' must have a '[Symbol.iterator]()' method that returns an iteratorTS2488:键入“字符串 | null' 必须有一个返回迭代器的 '[Symbol.iterator]()' 方法
【发布时间】:2020-11-14 04:56:27
【问题描述】:

我正在尝试将 https://github.com/camwiegert/typical/blob/master/typical.js 转换为 TypeScript。

在 Vanilla JS 中,它看起来像:

典型的.js

export async function type(node, ...args) {
    for (const arg of args) {
        switch (typeof arg) {
            case 'string':
                await edit(node, arg);
                break;
            case 'number':
                await wait(arg);
                break;
            case 'function':
                await arg(node, ...args);
                break;
            default:
                await arg;
        }
    }
}

async function edit(node, text) {
    const overlap = getOverlap(node.textContent, text);
    await perform(node, [...deleter(node.textContent, overlap), ...writer(text, overlap)]);
}

async function wait(ms) {
    await new Promise(resolve => setTimeout(resolve, ms));
}

async function perform(node, edits, speed = 60) {
    for (const op of editor(edits)) {
        op(node);
        await wait(speed + speed * (Math.random() - 0.5));
    }
}

export function* editor(edits) {
    for (const edit of edits) {
        yield (node) => requestAnimationFrame(() => node.textContent = edit);
    }
}

export function* writer([...text], startIndex = 0, endIndex = text.length) {
    while (startIndex < endIndex) {
        yield text.slice(0, ++startIndex).join('');
    }
}

export function* deleter([...text], startIndex = 0, endIndex = text.length) {
    while (endIndex > startIndex) {
        yield text.slice(0, --endIndex).join('');
    }
}

export function getOverlap(start, [...end]) {
    return [...start, NaN].findIndex((char, i) => end[i] !== char);
}

我的 TS 转换如下:

典型的.ts

export async function type(node: HTMLElement, ...args: any[]): Promise<void> {
  for (const arg of args) {
    switch (typeof arg) {
      case 'string':
        await edit(node, arg);
        break;
      case 'number':
        await wait(arg);
        break;
      case 'function':
        await arg(node, ...args);
        break;
      default:
        await arg;
    }
  }
}

async function edit(node: HTMLElement, text: string): Promise<void> {
  const overlap = getOverlap(node.textContent, text);
  await perform(node, [
    ...deleter(node.textContent, overlap),
    ...writer(text, overlap),
  ]);
}

async function wait(ms: number): Promise<void> {
  await new Promise(resolve => setTimeout(resolve, ms));
}

async function perform(
  node: HTMLElement,
  edits: Iterable<string | null>,
  speed: number = 60
): Promise<void> {
  for (const op of editor(edits)) {
    op(node);
    await wait(speed + speed * (Math.random() - 0.5));
  }
}

export function* editor(
  edits: Iterable<string | null>
): Generator<(node: any) => number, void, unknown> {
  for (const edit of edits) {
    yield node => requestAnimationFrame(() => (node.textContent = edit));
  }
}

export function* writer(
  [...text]: string,
  startIndex: number = 0,
  endIndex: number = text.length
): Generator<string, void, unknown> {
  while (startIndex < endIndex) {
    yield text.slice(0, ++startIndex).join('');
  }
}

export function* deleter(
  [...text]: string | null,
  startIndex: number = 0,
  endIndex: number = text.length
): Generator<string, void, unknown> {
  while (endIndex > startIndex) {
    yield text.slice(0, --endIndex).join('');
  }
}

export function getOverlap(start: any, [...end]: Iterable<any>): number {
  return [...start, NaN].findIndex((char, i) => end[i] !== char);
}

大多数情况下,我按照 VSCode 关于悬停的建议进行输入和一些逻辑。

但是,它给了我一个错误提示:

typical.ts(61,3): 语义错误 TS2488: Type 'string | null' 必须有一个返回迭代器的 'Symbol.iterator' 方法。

第61行是deleter()函数的[...text],即:

[...text]: string | null,

我该如何解决这个问题?

【问题讨论】:

  • @NikitaMadeev 我已经设置好了

标签: javascript node.js typescript asynchronous iterator


【解决方案1】:

所以,来自函数deleter[...text] 参数实际上是一个字符数组。 例如,考虑这个电话deleter(node.textContent, overlap)node.textContent 的类型可以是stringnull,参数类型是[...text]: string | null,但textContent 可以是null,您不能将其解构为[...text]。会有两条路径。

  1. [...text] = node.textContent
  2. [...text] = null

第二个无效,这就是您收到此类型错误的原因。 您可以将功能更改为

export function* deleter(
  text: string | null,
  startIndex: number = 0
): Generator<string, void, unknown> {
  if (text === null) {
    yield ""// Or throw
    return
  }
  const [...chars] = text
  let endIndex = chars.length
  while (endIndex > startIndex) {
    yield chars.slice(0, --endIndex).join("");
  }
}

更新 1:
Path was expected to have a container! 错误可以通过在开关盒主体周围添加花括号 {...} 来解决。 喜欢。

case 'string':
{
  await edit(node, arg);
}
break;

unknown Statement of type "ForOfStatement" 错误可以通过添加正确的 babel 配置来解决。 这是正确的配置。

//.babelrc.js
module.exports = {
  "presets": [
    [
      "@babel/env",
      {
        "targets": {
          "browsers": "last 2 Chrome versions",
          "node": "current"
        }
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-transform-for-of",
    ['@babel/plugin-transform-runtime',
      {
        helpers: false
      }
    ],
    "@babel/plugin-transform-destructuring"
  ]
}

【讨论】:

  • 确实有道理。但是,我遇到了另一个错误 Path was expected to have a container! 指向 switch 附近
  • 究竟在哪一行?
  • switch 之一。行号3 在字符s.
  • 这其实很奇怪。 arg 的显式类型是 any。
  • 不确定我是否关注?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-28
  • 1970-01-01
  • 2020-03-19
  • 2019-12-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多