function evaluateQuasis(
  path: NodePath<t.TaggedTemplateExpression | t.TemplateLiteral>,
  quasis: Array<any>,
  state: State,
  raw: boolean = false,
) {
  let str = '';

  let i = 0;
  const exprs: $ReadOnlyArray<NodePath<>> = path.isTemplateLiteral()
    ? path.get('expressions')
    : path.isTaggedTemplateExpression()
      ? path.get('quasi').get('expressions')
      : [];

  // const exprs: Array<NodePath<t.Node>> = path.isTemplateLiteral()
  //   ? path.get('expressions')
  //   : (path as NodePath<t.TaggedTemplateExpression>)
  //       .get('quasi')
  //       .get('expressions');

  for (const elem of quasis) {
    // not confident, evaluated an expression we don't like
    if (!state.confident) break;

    // add on element
    str += raw ? elem.value.raw : elem.value.cooked;

    // add on interpolated expression if it's present
    const expr = exprs[i++];
    if (expr) str += String(evaluateCached(expr, state));
  }

  if (!state.confident) return;
  return str;
}
We wrap the _evaluate method so we can track `seen` nodes, we push an item
to the map before we actually evaluate it so we can deopt on self recursive
nodes such as:

  var g = a ? 1 : 2,
      a = g * this.foo