function flattenTypeNodes(context, node) {
  /**
   * @typedef {object} TraversedData
   * @property {Set<TSESTreeTypeNode|TSESTreeTSInterfaceBody>} nodes
   * @property {boolean} finished
   */
  /** @type {Map<TSESTreeTypeNode,TraversedData>} */
  const traversed = new Map()

  return [...flattenImpl(node)]
  /**
   * @param {TSESTreeTypeNode} node
   * @returns {Iterable<TSESTreeTypeNode|TSESTreeTSInterfaceBody>}
   */
  function* flattenImpl(node) {
    if (node.type === 'TSUnionType' || node.type === 'TSIntersectionType') {
      for (const typeNode of node.types) {
        yield* flattenImpl(typeNode)
      }
      return
    }
    if (
      node.type === 'TSTypeReference' &&
      node.typeName.type === 'Identifier'
    ) {
      const refName = node.typeName.name
      const variable = findVariable(
        getScope(context, /** @type {any} */ (node)),
        refName
      )
      if (variable && variable.defs.length === 1) {
        const defNode = /** @type {TSESTreeNode} */ (variable.defs[0].node)
        if (defNode.type === 'TSInterfaceDeclaration') {
          yield defNode.body
          return
        } else if (defNode.type === 'TSTypeAliasDeclaration') {
          const typeAnnotation = defNode.typeAnnotation
          let traversedData = traversed.get(typeAnnotation)
          if (traversedData) {
            const copy = [...traversedData.nodes]
            yield* copy
            if (!traversedData.finished) {
              // Include the node because it will probably be referenced recursively.
              yield typeAnnotation
            }
            return
          }
          traversedData = { nodes: new Set(), finished: false }
          traversed.set(typeAnnotation, traversedData)
          for (const e of flattenImpl(typeAnnotation)) {
            traversedData.nodes.add(e)
          }
          traversedData.finished = true
          yield* traversedData.nodes
          return
        }
      }
    }
    yield node
  }
}
@param {RuleContext} context The ESLint rule context object.
@param {TSESTreeTypeNode} node
@returns {(TSESTreeTypeNode|TSESTreeTSInterfaceBody)[]}