'Get AST nodes typescript name from SpreadOperator RuleListener Identifier node argument

I would like to get the node.argument properties Typescript types name, and check if it's Foo.

Let's say the Foo type is defined like this:

type Foo = {};

This is my eslint rule definition so far.

import { createRule, } from "../utils";

export default createRule({
    name: 'disallow-foo-type-spread',
    meta: {
      type: 'suggestion',
      docs: {
        description: 'Bans spread operator from being used on foo.',
        recommended: 'error',
      },
      messages: {
        noSpread: "Don't spread foo"
      },
      schema:[{}]
    },
    defaultOptions: [{}],
    create(context) {
        return {
          
          SpreadElement(node) {
              console.log(node.argument);

             if (node.argument.typeName === "Foo") {
                context.report({
                  node,
                  messageId: "noSpread",
                });
             }
          },
        };
    }
  });

However the typeName is undefined. Using astexplorer.net https://astexplorer.net/#/gist/c6a63070e9678f906f1c61d3087d8027/f659343aa025059f2220d27217cb6b03d733e92b

If we use asteexplorer.net to inspect the following code: https://astexplorer.net/#/gist/c6a63070e9678f906f1c61d3087d8027/f659343aa025059f2220d27217cb6b03d733e92b

type Foo = {};


const foo: Foo = {}


const moo = {...foo}

We can see that the ...foo node that triggers the SpreadElement RuleListener does not have the Foo type in it at all.

My question is. How do I check if the node that triggered SpreadElement rulelistener is of type Foo or something else?



Solution 1:[1]

Seems this works:

import { ESLintUtils } from "@typescript-eslint/utils";

...

create(context) {
    const parserServices = ESLintUtils.getParserServices(context);
    const checker = parserServices?.program?.getTypeChecker();
    return {
      
      SpreadElement(node) {
         const expression = parserServices.esTreeNodeToTSNodeMap.get(
           node.argument
         );
         const symbol = checker?.getTypeAtLocation(expression)?.getSymbol();
          const type = symbol?.escapedName?.toString() || "";
          

         if (type === "Foo") {
            context.report({
              node,
              messageId: "noSpread",
            });
         }
      },
    };
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Waltari