【问题标题】:(babel plugin) TypeError: Path was expected to have a container(babel plugin) TypeError: Path was expected to have a container
【发布时间】:2020-11-15 02:16:13
【问题描述】:

我正在尝试将 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);
}

在 TypeScript 中,它看起来像:

典型的.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
): Generator<string, void, unknown> {
  if (text === null) {
    yield '';
    return;
  }
  const [...chars] = text;
  let endIndex = chars.length;
  while (endIndex > startIndex) {
    yield chars.slice(0, --endIndex).join('');
  }
}

export function getOverlap(start: string | null, [...end]: string): number {
  if (start === null) return 0;
  return [...start, NaN].findIndex((char, i) => end[i] !== char);
}

我收到一条错误消息 Path was expected to have a container!,但我没有收到。它在终端中显示以下内容:

1 | export async function type(node, ...args) {
  2 |     for (const arg of args) {
> 3 |         switch (typeof arg) {
    |         ^
  4 |             case 'string':
  5 |                 await edit(node, arg);
  6 |                 break;
TypeError: ~/react-typical/src/typical.ts: Path was expected to have a container!
  1 | export async function type(node, ...args) {
  2 |     for (const arg of args) {
> 3 |         switch (typeof arg) {
    |         ^
  4 |             case 'string':
  5 |                 await edit(node, arg);
  6 |                 break;
    at File.buildCodeFrameError (~/react-typical/node_modules/@babel/core/lib/transformation/file/file.js:248:12)
    at NodePath.buildCodeFrameError (~/react-typical/node_modules/@babel/traverse/lib/path/index.js:144:21)
    at checkPathValidity (~/react-typical/node_modules/babel-plugin-transform-async-to-promises/async-to-promises.js:1085:24)
    at relocateTail (~/react-typical/node_modules/babel-plugin-transform-async-to-promises/async-to-promises.js:1095:9)
    at Object.rewriteAwaitOrYieldPath (~/react-typical/node_modules/babel-plugin-transform-async-to-promises/async-to-promises.js:2685:21)
    at NodePath._call (~/react-typical/node_modules/@babel/traverse/lib/path/context.js:55:20)
    at NodePath.call (~/react-typical/node_modules/@babel/traverse/lib/path/context.js:42:17)
    at NodePath.visit (~/react-typical/node_modules/@babel/traverse/lib/path/context.js:90:31)
    at TraversalContext.visitQueue (~/react-typical/node_modules/@babel/traverse/lib/context.js:112:16)
    at TraversalContext.visitSingle (~/react-typical/node_modules/@babel/traverse/lib/context.js:84:19)

我该如何解决这个问题?

【问题讨论】:

  • 您能否发布您的 babel 配置以及您使用的版本包,例如 babel 和预设?
  • @tmhao2005 我正在使用tsdx.io,所以这就是它的全部用途。我也将 repo 上传到了 github,所以你可以检查它here

标签: javascript node.js typescript asynchronous promise


【解决方案1】:

经过一番调试,我发现问题来自这个包babel-plugin-transform-async-to-promises,它与switch/case过程有关。我没有深入研究太多代码,但我怀疑块范围很重要,所以我将您的案例改进为新范围,然后它的工作方式如下:

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

完整代码如下:

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

【讨论】:

  • 这确实有效,我早点想通了,必须安装一些 babel 包并上传 .babelrc,查看我在 Github 上的最新提交,但我遇到了另一个错误。我遇到了另一个错误:(babel plugin) TypeError: /react-typical/src/typical.ts: Property name expected type of string but got null
  • 那我试试拉看看
  • 我找到了验证步骤,因为您将"node": "current" 设置为目标的一部分。似乎它验证了这个值。您是否创建它以针对节点 env 运行?
  • 如果是这样,我猜你不必将目标设置为节点
  • 是的,我删除了它:)
【解决方案2】:

当您针对节点转换代码时,我还发现了一些有趣的东西。您从 word 中传播字符的方式不起作用,因此您可能需要更改它:

// const [...chars] = text;
const chars = Array.from(text);

【讨论】:

  • 不,两者都可以正常工作。在devtools &gt; console 中尝试const [...chars] = 'hello' & const chars2 = Array.from('hello') & 都给出相同的结果
  • 是的,它看起来工作正常,但是让我们检查一下你的目标是你配置的节点。让我们改变那行然后你会看到
  • 该死的,这行得通。太感谢了。你让我开心:)
猜你喜欢
  • 1970-01-01
  • 2022-12-01
  • 2021-02-25
  • 1970-01-01
  • 2022-12-02
  • 1970-01-01
  • 2018-07-13
  • 2021-05-04
  • 1970-01-01
相关资源
最近更新 更多