Skip to content

⬅️ Back to Table of Contents

📄 no-unsafe-assignment

📊 Analysis Summary

Metric Count
🔧 Functions 8
📦 Imports 13
🎯 Enums 1

📚 Table of Contents

🛠️ File Location:

📂 packages/eslint-plugin/src/rules/no-unsafe-assignment.ts

📤 Default Export

export default createRule({ ... })
Property Value
name 'no-unsafe-assignment'
meta.type 'problem'
meta.docs.description 'Disallow assigning a value with type any to variables and properties'
meta.docs.recommended 'recommended'
meta.docs.requiresTypeChecking true
meta.messages.anyAssignment 'Unsafe assignment of an {{sender}} value.'
meta.messages.anyAssignmentThis [ 'Unsafe assignment of an {{sender}} value. this is typed as any.', 'You can try to fix this by turning on the `...
meta.messages.unsafeArrayPattern 'Unsafe array destructuring of an {{sender}} array value.'
meta.messages.unsafeArrayPatternFromTuple 'Unsafe array destructuring of a tuple element with an {{sender}} value.'
meta.messages.unsafeArraySpread 'Unsafe spread of an {{sender}} value in an array.'
meta.messages.unsafeAssignment 'Unsafe assignment of type {{sender}} to a variable of type {{receiver}}.'
meta.messages.unsafeObjectPattern 'Unsafe object destructuring of a property with an {{sender}} value.'
meta.schema []
defaultOptions []

Entry point: create — documented under Functions.


📦 Imports

Name Source
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
createRule ../util
getConstrainedTypeAtLocation ../util
getContextualType ../util
getParserServices ../util
getThisExpression ../util
isTypeAnyArrayType ../util
isTypeAnyType ../util
isTypeUnknownType ../util
isUnsafeAssignment ../util
nullThrows ../util
NullThrowsReasons ../util

Functions

create(context: any): { 'AccessorProperty[value != null]'(node: { value: object; …

Parameters:

  • context any

Returns: { 'AccessorProperty[value != null]'(node: { value: object; } & TSESTree.AccessorProperty): void; 'AssignmentExpression[operator = "="], AssignmentPattern'(node: TSESTree.AssignmentExpression | TSESTree.AssignmentPattern): void; 'PropertyDefinition[value != null]'(node: { value: object; } & TSESTree.PropertyDefinition): void; 'VariableDeclarator[init != null]'(node: TSESTree.VariableDeclarator): void; ':not(ObjectPattern) > Property'(node: TSESTree.Property): void; 'ArrayExpression > SpreadElement'(node: TSESTree.SpreadElement): void; 'JSXAttribute[value != null]'(node: TSESTree.JSXAttribute): void; }

Calls:

  • getParserServices (from ../util)
  • services.program.getTypeChecker
  • services.program.getCompilerOptions
  • tsutils.isStrictCompilerOptionEnabled
  • services.esTreeNodeToTSNodeMap.get
  • services.getTypeAtLocation
  • checkArrayDestructure
  • isTypeAnyArrayType (from ../util)
  • context.report
  • createData
  • checker.isTupleType
  • checker.getTypeArguments
  • isTypeAnyType (from ../util)
  • checkObjectDestructure
  • senderType .getProperties() .map
  • property.getName
  • checker.getTypeOfSymbolAtLocation
  • String
  • nullThrows (from ../util)
  • properties.get
  • getContextualType (from ../util)
  • isTypeUnknownType (from ../util)
  • getThisExpression (from ../util)
  • getConstrainedTypeAtLocation (from ../util)
  • isUnsafeAssignment (from ../util)
  • checker.typeToString
  • tsutils.isIntrinsicErrorType
  • checkAssignment
  • getComparisonType
  • checkArrayDestructureHelper
  • checkObjectDestructureHelper
  • NullThrowsReasons.MissingToken

Internal Comments:

// returns true if the assignment reported (x5)
// any array
// const [x] = ([] as any[]);
// tuple with any (x2)
// const [x] = [1 as any]; (x2)
// don't handle rests as they're not a 1:1 assignment
// check for the any type first so we can handle [[[x]]] = [any]
// we want to report on every invalid element in the tuple (x3)
// don't bother checking rest
// can't figure out the name, so skip it
// check for the any type first so we can handle {x: {y: z}} = {x: any}
// handle cases when we assign any ==> unknown.
// `var foo = this` (x2)
// the variable already has some form of a type to compare against (x2)
// object pattern props are checked via assignments (x2)
// handled by other selector

Code
create(context) {
    const services = getParserServices(context);
    const checker = services.program.getTypeChecker();
    const compilerOptions = services.program.getCompilerOptions();
    const isNoImplicitThis = tsutils.isStrictCompilerOptionEnabled(
      compilerOptions,
      'noImplicitThis',
    );

    // returns true if the assignment reported
    function checkArrayDestructureHelper(
      receiverNode: TSESTree.Node,
      senderNode: TSESTree.Node,
    ): boolean {
      if (receiverNode.type !== AST_NODE_TYPES.ArrayPattern) {
        return false;
      }

      const senderTsNode = services.esTreeNodeToTSNodeMap.get(senderNode);
      const senderType = services.getTypeAtLocation(senderNode);

      return checkArrayDestructure(receiverNode, senderType, senderTsNode);
    }

    // returns true if the assignment reported
    function checkArrayDestructure(
      receiverNode: TSESTree.ArrayPattern,
      senderType: ts.Type,
      senderNode: ts.Node,
    ): boolean {
      // any array
      // const [x] = ([] as any[]);
      if (isTypeAnyArrayType(senderType, checker)) {
        context.report({
          node: receiverNode,
          messageId: 'unsafeArrayPattern',
          data: createData(senderType),
        });
        return false;
      }

      if (!checker.isTupleType(senderType)) {
        return true;
      }

      const tupleElements = checker.getTypeArguments(senderType);

      // tuple with any
      // const [x] = [1 as any];
      let didReport = false;
      for (
        let receiverIndex = 0;
        receiverIndex < receiverNode.elements.length;
        receiverIndex += 1
      ) {
        const receiverElement = receiverNode.elements[receiverIndex];
        if (!receiverElement) {
          continue;
        }

        if (receiverElement.type === AST_NODE_TYPES.RestElement) {
          // don't handle rests as they're not a 1:1 assignment
          continue;
        }

        const senderType = tupleElements[receiverIndex] as ts.Type | undefined;
        if (!senderType) {
          continue;
        }

        // check for the any type first so we can handle [[[x]]] = [any]
        if (isTypeAnyType(senderType)) {
          context.report({
            node: receiverElement,
            messageId: 'unsafeArrayPatternFromTuple',
            data: createData(senderType),
          });
          // we want to report on every invalid element in the tuple
          didReport = true;
        } else if (receiverElement.type === AST_NODE_TYPES.ArrayPattern) {
          didReport = checkArrayDestructure(
            receiverElement,
            senderType,
            senderNode,
          );
        } else if (receiverElement.type === AST_NODE_TYPES.ObjectPattern) {
          didReport = checkObjectDestructure(
            receiverElement,
            senderType,
            senderNode,
          );
        }
      }

      return didReport;
    }

    // returns true if the assignment reported
    function checkObjectDestructureHelper(
      receiverNode: TSESTree.Node,
      senderNode: TSESTree.Node,
    ): boolean {
      if (receiverNode.type !== AST_NODE_TYPES.ObjectPattern) {
        return false;
      }

      const senderTsNode = services.esTreeNodeToTSNodeMap.get(senderNode);
      const senderType = services.getTypeAtLocation(senderNode);

      return checkObjectDestructure(receiverNode, senderType, senderTsNode);
    }

    // returns true if the assignment reported
    function checkObjectDestructure(
      receiverNode: TSESTree.ObjectPattern,
      senderType: ts.Type,
      senderNode: ts.Node,
    ): boolean {
      const properties = new Map(
        senderType
          .getProperties()
          .map(property => [
            property.getName(),
            checker.getTypeOfSymbolAtLocation(property, senderNode),
          ]),
      );

      let didReport = false;
      for (const receiverProperty of receiverNode.properties) {
        if (receiverProperty.type === AST_NODE_TYPES.RestElement) {
          // don't bother checking rest
          continue;
        }

        let key: string;
        if (!receiverProperty.computed) {
          key =
            receiverProperty.key.type === AST_NODE_TYPES.Identifier
              ? receiverProperty.key.name
              : String(receiverProperty.key.value);
        } else if (receiverProperty.key.type === AST_NODE_TYPES.Literal) {
          key = String(receiverProperty.key.value);
        } else if (
          receiverProperty.key.type === AST_NODE_TYPES.TemplateLiteral &&
          receiverProperty.key.quasis.length === 1
        ) {
          const cooked = nullThrows(
            receiverProperty.key.quasis[0].value.cooked,
            'cooked can only be null inside a TaggedTemplateExpression, which is not possible here',
          );
          key = cooked;
        } else {
          // can't figure out the name, so skip it
          continue;
        }

        const senderType = properties.get(key);
        if (!senderType) {
          continue;
        }

        // check for the any type first so we can handle {x: {y: z}} = {x: any}
        if (isTypeAnyType(senderType)) {
          context.report({
            node: receiverProperty.value,
            messageId: 'unsafeObjectPattern',
            data: createData(senderType),
          });
          didReport = true;
        } else if (
          receiverProperty.value.type === AST_NODE_TYPES.ArrayPattern
        ) {
          didReport = checkArrayDestructure(
            receiverProperty.value,
            senderType,
            senderNode,
          );
        } else if (
          receiverProperty.value.type === AST_NODE_TYPES.ObjectPattern
        ) {
          didReport = checkObjectDestructure(
            receiverProperty.value,
            senderType,
            senderNode,
          );
        }
      }

      return didReport;
    }

    // returns true if the assignment reported
    function checkAssignment(
      receiverNode: TSESTree.Node,
      senderNode: TSESTree.Expression,
      reportingNode: TSESTree.Node,
      comparisonType: ComparisonType,
    ): boolean {
      const receiverTsNode = services.esTreeNodeToTSNodeMap.get(receiverNode);
      const receiverType =
        comparisonType === ComparisonType.Contextual
          ? (getContextualType(checker, receiverTsNode as ts.Expression) ??
            services.getTypeAtLocation(receiverNode))
          : services.getTypeAtLocation(receiverNode);
      const senderType = services.getTypeAtLocation(senderNode);

      if (isTypeAnyType(senderType)) {
        // handle cases when we assign any ==> unknown.
        if (isTypeUnknownType(receiverType)) {
          return false;
        }

        let messageId: 'anyAssignment' | 'anyAssignmentThis' = 'anyAssignment';

        if (!isNoImplicitThis) {
          // `var foo = this`
          const thisExpression = getThisExpression(senderNode);
          if (
            thisExpression &&
            isTypeAnyType(
              getConstrainedTypeAtLocation(services, thisExpression),
            )
          ) {
            messageId = 'anyAssignmentThis';
          }
        }

        context.report({
          node: reportingNode,
          messageId,
          data: createData(senderType),
        });

        return true;
      }

      if (comparisonType === ComparisonType.None) {
        return false;
      }

      const result = isUnsafeAssignment(
        senderType,
        receiverType,
        checker,
        senderNode,
      );
      if (!result) {
        return false;
      }

      const { receiver, sender } = result;
      context.report({
        node: reportingNode,
        messageId: 'unsafeAssignment',
        data: createData(sender, receiver),
      });
      return true;
    }

    function getComparisonType(
      typeAnnotation: TSESTree.TSTypeAnnotation | undefined,
    ): ComparisonType {
      return typeAnnotation
        ? // if there's a type annotation, we can do a comparison
          ComparisonType.Basic
        : // no type annotation means the variable's type will just be inferred, thus equal
          ComparisonType.None;
    }

    function createData(
      senderType: ts.Type,
      receiverType?: ts.Type,
    ): Readonly<Record<string, unknown>> | undefined {
      if (receiverType) {
        return {
          receiver: `\`${checker.typeToString(receiverType)}\``,
          sender: `\`${checker.typeToString(senderType)}\``,
        };
      }
      return {
        sender: tsutils.isIntrinsicErrorType(senderType)
          ? 'error typed'
          : '`any`',
      };
    }

    return {
      'AccessorProperty[value != null]'(
        node: { value: object } & TSESTree.AccessorProperty,
      ): void {
        checkAssignment(
          node.key,
          node.value,
          node,
          getComparisonType(node.typeAnnotation),
        );
      },
      'AssignmentExpression[operator = "="], AssignmentPattern'(
        node: TSESTree.AssignmentExpression | TSESTree.AssignmentPattern,
      ): void {
        let didReport = checkAssignment(
          node.left,
          node.right,
          node,
          // the variable already has some form of a type to compare against
          ComparisonType.Basic,
        );

        if (!didReport) {
          didReport = checkArrayDestructureHelper(node.left, node.right);
        }
        if (!didReport) {
          checkObjectDestructureHelper(node.left, node.right);
        }
      },
      'PropertyDefinition[value != null]'(
        node: { value: object } & TSESTree.PropertyDefinition,
      ): void {
        checkAssignment(
          node.key,
          node.value,
          node,
          getComparisonType(node.typeAnnotation),
        );
      },
      'VariableDeclarator[init != null]'(
        node: TSESTree.VariableDeclarator,
      ): void {
        const init = nullThrows(
          node.init,
          NullThrowsReasons.MissingToken(node.type, 'init'),
        );
        let didReport = checkAssignment(
          node.id,
          init,
          node,
          getComparisonType(node.id.typeAnnotation),
        );

        if (!didReport) {
          didReport = checkArrayDestructureHelper(node.id, init);
        }
        if (!didReport) {
          checkObjectDestructureHelper(node.id, init);
        }
      },
      // object pattern props are checked via assignments
      ':not(ObjectPattern) > Property'(node: TSESTree.Property): void {
        if (
          node.value.type === AST_NODE_TYPES.AssignmentPattern ||
          node.value.type === AST_NODE_TYPES.TSEmptyBodyFunctionExpression
        ) {
          // handled by other selector
          return;
        }

        checkAssignment(node.key, node.value, node, ComparisonType.Contextual);
      },
      'ArrayExpression > SpreadElement'(node: TSESTree.SpreadElement): void {
        const restType = services.getTypeAtLocation(node.argument);
        if (isTypeAnyType(restType) || isTypeAnyArrayType(restType, checker)) {
          context.report({
            node,
            messageId: 'unsafeArraySpread',
            data: createData(restType),
          });
        }
      },
      'JSXAttribute[value != null]'(node: TSESTree.JSXAttribute): void {
        const value = nullThrows(
          node.value,
          NullThrowsReasons.MissingToken(node.type, 'value'),
        );
        if (
          value.type !== AST_NODE_TYPES.JSXExpressionContainer ||
          value.expression.type === AST_NODE_TYPES.JSXEmptyExpression
        ) {
          return;
        }

        checkAssignment(
          node.name,
          value.expression,
          value.expression,
          ComparisonType.Contextual,
        );
      },
    };
  }

Internal helpers

Declared inside another function in this file.

checkArrayDestructureHelper(receiverNode: TSESTree.Node, senderNode: TSESTree.Node): boolean

Parameters:

  • receiverNode TSESTree.Node
  • senderNode TSESTree.Node

Returns: boolean

Calls:

  • services.esTreeNodeToTSNodeMap.get
  • services.getTypeAtLocation
  • checkArrayDestructure
Code
function checkArrayDestructureHelper(
      receiverNode: TSESTree.Node,
      senderNode: TSESTree.Node,
    ): boolean {
      if (receiverNode.type !== AST_NODE_TYPES.ArrayPattern) {
        return false;
      }

      const senderTsNode = services.esTreeNodeToTSNodeMap.get(senderNode);
      const senderType = services.getTypeAtLocation(senderNode);

      return checkArrayDestructure(receiverNode, senderType, senderTsNode);
    }

checkArrayDestructure(receiverNode: TSESTree.ArrayPattern, senderType: ts.Type, senderNode: ts.Node): boolean

Parameters:

  • receiverNode TSESTree.ArrayPattern
  • senderType ts.Type
  • senderNode ts.Node

Returns: boolean

Calls:

  • isTypeAnyArrayType (from ../util)
  • context.report
  • createData
  • checker.isTupleType
  • checker.getTypeArguments
  • isTypeAnyType (from ../util)
  • checkArrayDestructure
  • checkObjectDestructure

Internal Comments:

// any array
// const [x] = ([] as any[]);
// tuple with any (x2)
// const [x] = [1 as any]; (x2)
// don't handle rests as they're not a 1:1 assignment
// check for the any type first so we can handle [[[x]]] = [any]
// we want to report on every invalid element in the tuple (x3)

Code
function checkArrayDestructure(
      receiverNode: TSESTree.ArrayPattern,
      senderType: ts.Type,
      senderNode: ts.Node,
    ): boolean {
      // any array
      // const [x] = ([] as any[]);
      if (isTypeAnyArrayType(senderType, checker)) {
        context.report({
          node: receiverNode,
          messageId: 'unsafeArrayPattern',
          data: createData(senderType),
        });
        return false;
      }

      if (!checker.isTupleType(senderType)) {
        return true;
      }

      const tupleElements = checker.getTypeArguments(senderType);

      // tuple with any
      // const [x] = [1 as any];
      let didReport = false;
      for (
        let receiverIndex = 0;
        receiverIndex < receiverNode.elements.length;
        receiverIndex += 1
      ) {
        const receiverElement = receiverNode.elements[receiverIndex];
        if (!receiverElement) {
          continue;
        }

        if (receiverElement.type === AST_NODE_TYPES.RestElement) {
          // don't handle rests as they're not a 1:1 assignment
          continue;
        }

        const senderType = tupleElements[receiverIndex] as ts.Type | undefined;
        if (!senderType) {
          continue;
        }

        // check for the any type first so we can handle [[[x]]] = [any]
        if (isTypeAnyType(senderType)) {
          context.report({
            node: receiverElement,
            messageId: 'unsafeArrayPatternFromTuple',
            data: createData(senderType),
          });
          // we want to report on every invalid element in the tuple
          didReport = true;
        } else if (receiverElement.type === AST_NODE_TYPES.ArrayPattern) {
          didReport = checkArrayDestructure(
            receiverElement,
            senderType,
            senderNode,
          );
        } else if (receiverElement.type === AST_NODE_TYPES.ObjectPattern) {
          didReport = checkObjectDestructure(
            receiverElement,
            senderType,
            senderNode,
          );
        }
      }

      return didReport;
    }

checkObjectDestructureHelper(receiverNode: TSESTree.Node, senderNode: TSESTree.Node): boolean

Parameters:

  • receiverNode TSESTree.Node
  • senderNode TSESTree.Node

Returns: boolean

Calls:

  • services.esTreeNodeToTSNodeMap.get
  • services.getTypeAtLocation
  • checkObjectDestructure
Code
function checkObjectDestructureHelper(
      receiverNode: TSESTree.Node,
      senderNode: TSESTree.Node,
    ): boolean {
      if (receiverNode.type !== AST_NODE_TYPES.ObjectPattern) {
        return false;
      }

      const senderTsNode = services.esTreeNodeToTSNodeMap.get(senderNode);
      const senderType = services.getTypeAtLocation(senderNode);

      return checkObjectDestructure(receiverNode, senderType, senderTsNode);
    }

checkObjectDestructure(receiverNode: TSESTree.ObjectPattern, senderType: ts.Type, senderNode: ts.Node): boolean

Parameters:

  • receiverNode TSESTree.ObjectPattern
  • senderType ts.Type
  • senderNode ts.Node

Returns: boolean

Calls:

  • senderType .getProperties() .map
  • property.getName
  • checker.getTypeOfSymbolAtLocation
  • String
  • nullThrows (from ../util)
  • properties.get
  • isTypeAnyType (from ../util)
  • context.report
  • createData
  • checkArrayDestructure
  • checkObjectDestructure

Internal Comments:

// don't bother checking rest
// can't figure out the name, so skip it
// check for the any type first so we can handle {x: {y: z}} = {x: any}

Code
function checkObjectDestructure(
      receiverNode: TSESTree.ObjectPattern,
      senderType: ts.Type,
      senderNode: ts.Node,
    ): boolean {
      const properties = new Map(
        senderType
          .getProperties()
          .map(property => [
            property.getName(),
            checker.getTypeOfSymbolAtLocation(property, senderNode),
          ]),
      );

      let didReport = false;
      for (const receiverProperty of receiverNode.properties) {
        if (receiverProperty.type === AST_NODE_TYPES.RestElement) {
          // don't bother checking rest
          continue;
        }

        let key: string;
        if (!receiverProperty.computed) {
          key =
            receiverProperty.key.type === AST_NODE_TYPES.Identifier
              ? receiverProperty.key.name
              : String(receiverProperty.key.value);
        } else if (receiverProperty.key.type === AST_NODE_TYPES.Literal) {
          key = String(receiverProperty.key.value);
        } else if (
          receiverProperty.key.type === AST_NODE_TYPES.TemplateLiteral &&
          receiverProperty.key.quasis.length === 1
        ) {
          const cooked = nullThrows(
            receiverProperty.key.quasis[0].value.cooked,
            'cooked can only be null inside a TaggedTemplateExpression, which is not possible here',
          );
          key = cooked;
        } else {
          // can't figure out the name, so skip it
          continue;
        }

        const senderType = properties.get(key);
        if (!senderType) {
          continue;
        }

        // check for the any type first so we can handle {x: {y: z}} = {x: any}
        if (isTypeAnyType(senderType)) {
          context.report({
            node: receiverProperty.value,
            messageId: 'unsafeObjectPattern',
            data: createData(senderType),
          });
          didReport = true;
        } else if (
          receiverProperty.value.type === AST_NODE_TYPES.ArrayPattern
        ) {
          didReport = checkArrayDestructure(
            receiverProperty.value,
            senderType,
            senderNode,
          );
        } else if (
          receiverProperty.value.type === AST_NODE_TYPES.ObjectPattern
        ) {
          didReport = checkObjectDestructure(
            receiverProperty.value,
            senderType,
            senderNode,
          );
        }
      }

      return didReport;
    }

checkAssignment(receiverNode: TSESTree.Node, senderNode: TSESTree.Expression, reportingNode: TSESTree.Node, comparisonType: ComparisonType): boolean

Parameters:

  • receiverNode TSESTree.Node
  • senderNode TSESTree.Expression
  • reportingNode TSESTree.Node
  • comparisonType ComparisonType

Returns: boolean

Calls:

  • services.esTreeNodeToTSNodeMap.get
  • getContextualType (from ../util)
  • services.getTypeAtLocation
  • isTypeAnyType (from ../util)
  • isTypeUnknownType (from ../util)
  • getThisExpression (from ../util)
  • getConstrainedTypeAtLocation (from ../util)
  • context.report
  • createData
  • isUnsafeAssignment (from ../util)

Internal Comments:

// handle cases when we assign any ==> unknown.
// `var foo = this` (x2)

Code
function checkAssignment(
      receiverNode: TSESTree.Node,
      senderNode: TSESTree.Expression,
      reportingNode: TSESTree.Node,
      comparisonType: ComparisonType,
    ): boolean {
      const receiverTsNode = services.esTreeNodeToTSNodeMap.get(receiverNode);
      const receiverType =
        comparisonType === ComparisonType.Contextual
          ? (getContextualType(checker, receiverTsNode as ts.Expression) ??
            services.getTypeAtLocation(receiverNode))
          : services.getTypeAtLocation(receiverNode);
      const senderType = services.getTypeAtLocation(senderNode);

      if (isTypeAnyType(senderType)) {
        // handle cases when we assign any ==> unknown.
        if (isTypeUnknownType(receiverType)) {
          return false;
        }

        let messageId: 'anyAssignment' | 'anyAssignmentThis' = 'anyAssignment';

        if (!isNoImplicitThis) {
          // `var foo = this`
          const thisExpression = getThisExpression(senderNode);
          if (
            thisExpression &&
            isTypeAnyType(
              getConstrainedTypeAtLocation(services, thisExpression),
            )
          ) {
            messageId = 'anyAssignmentThis';
          }
        }

        context.report({
          node: reportingNode,
          messageId,
          data: createData(senderType),
        });

        return true;
      }

      if (comparisonType === ComparisonType.None) {
        return false;
      }

      const result = isUnsafeAssignment(
        senderType,
        receiverType,
        checker,
        senderNode,
      );
      if (!result) {
        return false;
      }

      const { receiver, sender } = result;
      context.report({
        node: reportingNode,
        messageId: 'unsafeAssignment',
        data: createData(sender, receiver),
      });
      return true;
    }

getComparisonType(typeAnnotation: TSESTree.TSTypeAnnotation | undefined): ComparisonType

Parameters:

  • typeAnnotation TSESTree.TSTypeAnnotation | undefined

Returns: ComparisonType

Code
function getComparisonType(
      typeAnnotation: TSESTree.TSTypeAnnotation | undefined,
    ): ComparisonType {
      return typeAnnotation
        ? // if there's a type annotation, we can do a comparison
          ComparisonType.Basic
        : // no type annotation means the variable's type will just be inferred, thus equal
          ComparisonType.None;
    }

createData(senderType: ts.Type, receiverType: ts.Type): Readonly<Record<string, unknown>> | undefined

Parameters:

  • senderType ts.Type
  • receiverType ts.Type

Returns: Readonly<Record<string, unknown>> | undefined

Calls:

  • checker.typeToString
  • tsutils.isIntrinsicErrorType
Code
function createData(
      senderType: ts.Type,
      receiverType?: ts.Type,
    ): Readonly<Record<string, unknown>> | undefined {
      if (receiverType) {
        return {
          receiver: `\`${checker.typeToString(receiverType)}\``,
          sender: `\`${checker.typeToString(senderType)}\``,
        };
      }
      return {
        sender: tsutils.isIntrinsicErrorType(senderType)
          ? 'error typed'
          : '`any`',
      };
    }

Enums

const enum ComparisonType

Enum Code
const enum ComparisonType {
  /** Do no assignment comparison */
  None,
  /** Use the receiver's type for comparison */
  Basic,
  /** Use the sender's contextual type for comparison */
  Contextual,
}

Members

Name Value Description
None auto / Do no assignment comparison */
Basic auto / Use the receiver's type for comparison */
Contextual auto / Use the sender's contextual type for comparison */

Generated by Syntax Scribe