Skip to content

⬅️ Back to Table of Contents

📄 no-type-alias

📊 Analysis Summary

Metric Count
🔧 Functions 8
📦 Imports 4
📐 Interfaces 1
📑 Type Aliases 4

📚 Table of Contents

🛠️ File Location:

📂 packages/eslint-plugin/src/rules/no-type-alias.ts

📤 Default Export

export default createRule<Options, MessageIds>({ ... })
Property Value
name 'no-type-alias'
meta.type 'suggestion'
meta.deprecated.deprecatedSince '6.0.0'
meta.deprecated.replacedBy [ { rule: { name: '@typescript-eslint/consistent-type-definitions', url: 'https://typescript-eslint.io/rules/consiste...
meta.deprecated.url 'https://github.com/typescript-eslint/typescript-eslint/pull/6229'
meta.docs.description 'Disallow type aliases'
meta.messages.noCompositionAlias '{{typeName}} in {{compositionType}} types are not allowed.'
meta.messages.noTypeAlias 'Type {{alias}} are not allowed.'
meta.schema [ { type: 'object', $defs: { expandedOptions: { type: 'string', enum: [ 'always', 'never', 'in-unions', 'in-intersect...
defaultOptions [ { allowAliases: 'never', allowCallbacks: 'never', allowConditionalTypes: 'never', allowConstructors: 'never', allow...

Entry point: create — documented under Functions.


📦 Imports

Name Source
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
AST_TOKEN_TYPES @typescript-eslint/utils
createRule ../util

Functions

create(context: any, [ { allowAliases, allowCallback…: any): { TSTypeAliasDeclaration(node: any): void; }

Parameters:

  • context any
  • [ { allowAliases, allowCallbacks, allowConditionalTypes, allowConstructors, allowGenerics, allowLiterals, allowMappedTypes, allowTupleTypes, }, ] any

Returns: { TSTypeAliasDeclaration(node: any): void; }

Calls:

  • compositions.includes
  • unions.includes
  • intersections.includes
  • context.report
  • type.toLowerCase
  • ['keyof', 'readonly'].includes
  • isSupportedComposition
  • reportError
  • checkAndReport
  • isValidTupleType
  • isValidGeneric
  • type.node.type.endsWith
  • aliasTypes.has
  • node.types.flatMap
  • getTypes
  • validateTypeAliases
  • types.forEach

Internal Comments:

/**
     * Determines if the composition type is supported by the allowed flags.
     * @param isTopLevel a flag indicating this is the top level node.
     * @param compositionType the composition type (either TSUnionType or TSIntersectionType)
     * @param allowed the currently allowed flags.
     */
/**
     * Gets the message to be displayed based on the node type and whether the node is a top level declaration.
     * @param node the location
     * @param compositionType the type of composition this alias is part of (undefined if not
     *                                  part of a composition)
     * @param isRoot a flag indicating we are dealing with the top level declaration.
     * @param type the kind of type alias being validated.
     */
/**
     * Validates the node looking for aliases, callbacks and literals.
     * @param type the type of composition this alias is part of (null if not
     *                                  part of a composition)
     * @param isTopLevel a flag indicating this is the top level node.
     */
// https://github.com/typescript-eslint/typescript-eslint/issues/5439
/* eslint-disable @typescript-eslint/no-non-null-assertion */
// callback
// conditional type
// literal object type (x3)
// mapped type (x3)
// tuple types (x3)
// alias / keyword (x3)
// unhandled type - shouldn't happen (x3)
/**
     * Flatten the given type into an array of its dependencies
     */
// is a top level type annotation (x3)
// is a composition type (x4)

Code
create(
    context,
    [
      {
        allowAliases,
        allowCallbacks,
        allowConditionalTypes,
        allowConstructors,
        allowGenerics,
        allowLiterals,
        allowMappedTypes,
        allowTupleTypes,
      },
    ],
  ) {
    const unions = ['always', 'in-unions', 'in-unions-and-intersections'];
    const intersections = [
      'always',
      'in-intersections',
      'in-unions-and-intersections',
    ];
    const compositions = [
      'in-unions',
      'in-intersections',
      'in-unions-and-intersections',
    ];
    const aliasTypes = new Set([
      AST_NODE_TYPES.TSArrayType,
      AST_NODE_TYPES.TSImportType,
      AST_NODE_TYPES.TSIndexedAccessType,
      AST_NODE_TYPES.TSLiteralType,
      AST_NODE_TYPES.TSTemplateLiteralType,
      AST_NODE_TYPES.TSTypeQuery,
      AST_NODE_TYPES.TSTypeReference,
    ]);

    /**
     * Determines if the composition type is supported by the allowed flags.
     * @param isTopLevel a flag indicating this is the top level node.
     * @param compositionType the composition type (either TSUnionType or TSIntersectionType)
     * @param allowed the currently allowed flags.
     */
    function isSupportedComposition(
      isTopLevel: boolean,
      compositionType: CompositionType | null,
      allowed: string,
    ): boolean {
      return (
        !compositions.includes(allowed) ||
        (!isTopLevel &&
          ((compositionType === AST_NODE_TYPES.TSUnionType &&
            unions.includes(allowed)) ||
            (compositionType === AST_NODE_TYPES.TSIntersectionType &&
              intersections.includes(allowed))))
      );
    }

    /**
     * Gets the message to be displayed based on the node type and whether the node is a top level declaration.
     * @param node the location
     * @param compositionType the type of composition this alias is part of (undefined if not
     *                                  part of a composition)
     * @param isRoot a flag indicating we are dealing with the top level declaration.
     * @param type the kind of type alias being validated.
     */
    function reportError(
      node: TSESTree.Node,
      compositionType: CompositionType | null,
      isRoot: boolean,
      type: string,
    ): void {
      if (isRoot) {
        return context.report({
          node,
          messageId: 'noTypeAlias',
          data: {
            alias: type.toLowerCase(),
          },
        });
      }

      return context.report({
        node,
        messageId: 'noCompositionAlias',
        data: {
          compositionType:
            compositionType === AST_NODE_TYPES.TSUnionType
              ? 'union'
              : 'intersection',
          typeName: type,
        },
      });
    }

    const isValidTupleType = (type: TypeWithLabel): boolean => {
      if (type.node.type === AST_NODE_TYPES.TSTupleType) {
        return true;
      }
      if (
        type.node.type === AST_NODE_TYPES.TSTypeOperator &&
        ['keyof', 'readonly'].includes(type.node.operator) &&
        type.node.typeAnnotation?.type === AST_NODE_TYPES.TSTupleType
      ) {
        return true;
      }
      return false;
    };

    const isValidGeneric = (type: TypeWithLabel): boolean => {
      return (
        type.node.type === AST_NODE_TYPES.TSTypeReference &&
        type.node.typeArguments != null
      );
    };

    const checkAndReport = (
      optionValue: Values,
      isTopLevel: boolean,
      type: TypeWithLabel,
      label: string,
    ): void => {
      if (
        optionValue === 'never' ||
        !isSupportedComposition(isTopLevel, type.compositionType, optionValue)
      ) {
        reportError(type.node, type.compositionType, isTopLevel, label);
      }
    };

    /**
     * Validates the node looking for aliases, callbacks and literals.
     * @param type the type of composition this alias is part of (null if not
     *                                  part of a composition)
     * @param isTopLevel a flag indicating this is the top level node.
     */
    function validateTypeAliases(
      type: TypeWithLabel,
      isTopLevel = false,
    ): void {
      // https://github.com/typescript-eslint/typescript-eslint/issues/5439
      /* eslint-disable @typescript-eslint/no-non-null-assertion */
      if (type.node.type === AST_NODE_TYPES.TSFunctionType) {
        // callback
        if (allowCallbacks === 'never') {
          reportError(type.node, type.compositionType, isTopLevel, 'Callbacks');
        }
      } else if (type.node.type === AST_NODE_TYPES.TSConditionalType) {
        // conditional type
        if (allowConditionalTypes === 'never') {
          reportError(
            type.node,
            type.compositionType,
            isTopLevel,
            'Conditional types',
          );
        }
      } else if (type.node.type === AST_NODE_TYPES.TSConstructorType) {
        if (allowConstructors === 'never') {
          reportError(
            type.node,
            type.compositionType,
            isTopLevel,
            'Constructors',
          );
        }
      } else if (type.node.type === AST_NODE_TYPES.TSTypeLiteral) {
        // literal object type
        checkAndReport(allowLiterals!, isTopLevel, type, 'Literals');
      } else if (type.node.type === AST_NODE_TYPES.TSMappedType) {
        // mapped type
        checkAndReport(allowMappedTypes!, isTopLevel, type, 'Mapped types');
      } else if (isValidTupleType(type)) {
        // tuple types
        checkAndReport(allowTupleTypes!, isTopLevel, type, 'Tuple Types');
      } else if (isValidGeneric(type)) {
        if (allowGenerics === 'never') {
          reportError(type.node, type.compositionType, isTopLevel, 'Generics');
        }
      } else if (
        type.node.type.endsWith(AST_TOKEN_TYPES.Keyword) ||
        aliasTypes.has(type.node.type) ||
        (type.node.type === AST_NODE_TYPES.TSTypeOperator &&
          (type.node.operator === 'keyof' ||
            (type.node.operator === 'readonly' &&
              type.node.typeAnnotation &&
              aliasTypes.has(type.node.typeAnnotation.type))))
      ) {
        // alias / keyword
        checkAndReport(allowAliases!, isTopLevel, type, 'Aliases');
      } else {
        // unhandled type - shouldn't happen
        reportError(type.node, type.compositionType, isTopLevel, 'Unhandled');
      }
      /* eslint-enable @typescript-eslint/no-non-null-assertion */
    }

    /**
     * Flatten the given type into an array of its dependencies
     */
    function getTypes(
      node: TSESTree.Node,
      compositionType: CompositionType | null = null,
    ): TypeWithLabel[] {
      if (
        node.type === AST_NODE_TYPES.TSUnionType ||
        node.type === AST_NODE_TYPES.TSIntersectionType
      ) {
        return node.types.flatMap(type => getTypes(type, node.type));
      }
      return [{ node, compositionType }];
    }

    return {
      TSTypeAliasDeclaration(node): void {
        const types = getTypes(node.typeAnnotation);
        if (types.length === 1) {
          // is a top level type annotation
          validateTypeAliases(types[0], true);
        } else {
          // is a composition type
          types.forEach(type => {
            validateTypeAliases(type);
          });
        }
      },
    };
  }

Internal helpers

Declared inside another function in this file.

isSupportedComposition(isTopLevel: boolean, compositionType: CompositionType | null, allowed: string): boolean

Determines if the composition type is supported by the allowed flags.

Parameters:

  • isTopLevel any: a flag indicating this is the top level node.
  • compositionType any: the composition type (either TSUnionType or TSIntersectionType)
  • allowed any: the currently allowed flags.
Raw JSDoc
/**
     * Determines if the composition type is supported by the allowed flags.
     * @param isTopLevel a flag indicating this is the top level node.
     * @param compositionType the composition type (either TSUnionType or TSIntersectionType)
     * @param allowed the currently allowed flags.
     */

Calls:

  • compositions.includes
  • unions.includes
  • intersections.includes
Code
function isSupportedComposition(
      isTopLevel: boolean,
      compositionType: CompositionType | null,
      allowed: string,
    ): boolean {
      return (
        !compositions.includes(allowed) ||
        (!isTopLevel &&
          ((compositionType === AST_NODE_TYPES.TSUnionType &&
            unions.includes(allowed)) ||
            (compositionType === AST_NODE_TYPES.TSIntersectionType &&
              intersections.includes(allowed))))
      );
    }

reportError(node: TSESTree.Node, compositionType: CompositionType | null, isRoot: boolean, type: string): void

Gets the message to be displayed based on the node type and whether the node is a top level declaration.

Parameters:

  • node any: the location
  • compositionType any: the type of composition this alias is part of (undefined if not part of a composition)
  • isRoot any: a flag indicating we are dealing with the top level declaration.
  • type any: the kind of type alias being validated.
Raw JSDoc
/**
     * Gets the message to be displayed based on the node type and whether the node is a top level declaration.
     * @param node the location
     * @param compositionType the type of composition this alias is part of (undefined if not
     *                                  part of a composition)
     * @param isRoot a flag indicating we are dealing with the top level declaration.
     * @param type the kind of type alias being validated.
     */

Calls:

  • context.report
  • type.toLowerCase
Code
function reportError(
      node: TSESTree.Node,
      compositionType: CompositionType | null,
      isRoot: boolean,
      type: string,
    ): void {
      if (isRoot) {
        return context.report({
          node,
          messageId: 'noTypeAlias',
          data: {
            alias: type.toLowerCase(),
          },
        });
      }

      return context.report({
        node,
        messageId: 'noCompositionAlias',
        data: {
          compositionType:
            compositionType === AST_NODE_TYPES.TSUnionType
              ? 'union'
              : 'intersection',
          typeName: type,
        },
      });
    }

isValidTupleType(type: TypeWithLabel): boolean

Parameters:

  • type TypeWithLabel

Returns: boolean

Calls:

  • ['keyof', 'readonly'].includes
Code
(type: TypeWithLabel): boolean => {
      if (type.node.type === AST_NODE_TYPES.TSTupleType) {
        return true;
      }
      if (
        type.node.type === AST_NODE_TYPES.TSTypeOperator &&
        ['keyof', 'readonly'].includes(type.node.operator) &&
        type.node.typeAnnotation?.type === AST_NODE_TYPES.TSTupleType
      ) {
        return true;
      }
      return false;
    }

isValidGeneric(type: TypeWithLabel): boolean

Parameters:

  • type TypeWithLabel

Returns: boolean

Code
(type: TypeWithLabel): boolean => {
      return (
        type.node.type === AST_NODE_TYPES.TSTypeReference &&
        type.node.typeArguments != null
      );
    }

checkAndReport(optionValue: Values, isTopLevel: boolean, type: TypeWithLabel, label: string): void

Parameters:

  • optionValue Values
  • isTopLevel boolean
  • type TypeWithLabel
  • label string

Returns: void

Calls:

  • isSupportedComposition
  • reportError
Code
(
      optionValue: Values,
      isTopLevel: boolean,
      type: TypeWithLabel,
      label: string,
    ): void => {
      if (
        optionValue === 'never' ||
        !isSupportedComposition(isTopLevel, type.compositionType, optionValue)
      ) {
        reportError(type.node, type.compositionType, isTopLevel, label);
      }
    }

validateTypeAliases(type: TypeWithLabel, isTopLevel: boolean): void

Validates the node looking for aliases, callbacks and literals.

Parameters:

  • type any: the type of composition this alias is part of (null if not part of a composition)
  • isTopLevel any: a flag indicating this is the top level node.
Raw JSDoc
/**
     * Validates the node looking for aliases, callbacks and literals.
     * @param type the type of composition this alias is part of (null if not
     *                                  part of a composition)
     * @param isTopLevel a flag indicating this is the top level node.
     */

Calls:

  • reportError
  • checkAndReport
  • isValidTupleType
  • isValidGeneric
  • type.node.type.endsWith
  • aliasTypes.has

Internal Comments:

// https://github.com/typescript-eslint/typescript-eslint/issues/5439
/* eslint-disable @typescript-eslint/no-non-null-assertion */
// callback
// conditional type
// literal object type (x3)
// mapped type (x3)
// tuple types (x3)
// alias / keyword (x3)
// unhandled type - shouldn't happen (x3)

Code
function validateTypeAliases(
      type: TypeWithLabel,
      isTopLevel = false,
    ): void {
      // https://github.com/typescript-eslint/typescript-eslint/issues/5439
      /* eslint-disable @typescript-eslint/no-non-null-assertion */
      if (type.node.type === AST_NODE_TYPES.TSFunctionType) {
        // callback
        if (allowCallbacks === 'never') {
          reportError(type.node, type.compositionType, isTopLevel, 'Callbacks');
        }
      } else if (type.node.type === AST_NODE_TYPES.TSConditionalType) {
        // conditional type
        if (allowConditionalTypes === 'never') {
          reportError(
            type.node,
            type.compositionType,
            isTopLevel,
            'Conditional types',
          );
        }
      } else if (type.node.type === AST_NODE_TYPES.TSConstructorType) {
        if (allowConstructors === 'never') {
          reportError(
            type.node,
            type.compositionType,
            isTopLevel,
            'Constructors',
          );
        }
      } else if (type.node.type === AST_NODE_TYPES.TSTypeLiteral) {
        // literal object type
        checkAndReport(allowLiterals!, isTopLevel, type, 'Literals');
      } else if (type.node.type === AST_NODE_TYPES.TSMappedType) {
        // mapped type
        checkAndReport(allowMappedTypes!, isTopLevel, type, 'Mapped types');
      } else if (isValidTupleType(type)) {
        // tuple types
        checkAndReport(allowTupleTypes!, isTopLevel, type, 'Tuple Types');
      } else if (isValidGeneric(type)) {
        if (allowGenerics === 'never') {
          reportError(type.node, type.compositionType, isTopLevel, 'Generics');
        }
      } else if (
        type.node.type.endsWith(AST_TOKEN_TYPES.Keyword) ||
        aliasTypes.has(type.node.type) ||
        (type.node.type === AST_NODE_TYPES.TSTypeOperator &&
          (type.node.operator === 'keyof' ||
            (type.node.operator === 'readonly' &&
              type.node.typeAnnotation &&
              aliasTypes.has(type.node.typeAnnotation.type))))
      ) {
        // alias / keyword
        checkAndReport(allowAliases!, isTopLevel, type, 'Aliases');
      } else {
        // unhandled type - shouldn't happen
        reportError(type.node, type.compositionType, isTopLevel, 'Unhandled');
      }
      /* eslint-enable @typescript-eslint/no-non-null-assertion */
    }

getTypes(node: TSESTree.Node, compositionType: CompositionType | null): TypeWithLabel[]

Flatten the given type into an array of its dependencies

Raw JSDoc
/**
     * Flatten the given type into an array of its dependencies
     */

Calls:

  • node.types.flatMap
  • getTypes
Code
function getTypes(
      node: TSESTree.Node,
      compositionType: CompositionType | null = null,
    ): TypeWithLabel[] {
      if (
        node.type === AST_NODE_TYPES.TSUnionType ||
        node.type === AST_NODE_TYPES.TSIntersectionType
      ) {
        return node.types.flatMap(type => getTypes(type, node.type));
      }
      return [{ node, compositionType }];
    }

Interfaces

TypeWithLabel

Interface Code
interface TypeWithLabel {
  compositionType: CompositionType | null;
  node: TSESTree.Node;
}

Properties

Name Type Optional Description
compositionType CompositionType \| null not shown
node TSESTree.Node not shown

Type Aliases

Values

type Values = | 'always'
  | 'in-intersections'
  | 'in-unions'
  | 'in-unions-and-intersections'
  | 'never';

Options

type Options = [
  {
    allowAliases?: Values;
    allowCallbacks?: 'always' | 'never';
    allowConditionalTypes?: 'always' | 'never';
    allowConstructors?: 'always' | 'never';
    allowGenerics?: 'always' | 'never';
    allowLiterals?: Values;
    allowMappedTypes?: Values;
    allowTupleTypes?: Values;
  },
];

MessageIds

type MessageIds = 'noCompositionAlias' | 'noTypeAlias';

CompositionType

type CompositionType = AST_NODE_TYPES.TSIntersectionType | AST_NODE_TYPES.TSUnionType;

Generated by Syntax Scribe