Skip to content

⬅️ Back to Table of Contents

📄 no-redundant-type-constituents.ts

📊 Analysis Summary

Metric Count
🔧 Functions 10
📦 Imports 11
📊 Variables & Constants 14
📐 Interfaces 3
📑 Type Aliases 1

📚 Table of Contents

🛠️ File Location:

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

📦 Imports

Name Source
AST_NODE_TYPES @typescript-eslint/utils
TSESTree @typescript-eslint/utils
arrayGroupByToMap ../util
createRule ../util
getParserServices ../util
isFunctionOrFunctionType ../util
isTypeAnyType ../util
isTypeBigIntLiteralType ../util
isTypeNeverType ../util
isTypeTemplateLiteralType ../util
isTypeUnknownType ../util

Variables & Constants

Name Type Kind Value Exported
literalToPrimitiveTypeFlags { readonly [x: number]: any; } const `{
[ts.TypeFlags.BigIntLiteral]: ts.TypeFlags.BigInt,
[ts.TypeFlags.BooleanLiteral]: ts.TypeFlags.Boolean,
[ts.TypeFlags.NumberLiteral]: ts.TypeFlags.Number,
[ts.TypeFlags.StringLiteral]: ts.TypeFlags.String,
[ts.TypeFlags.TemplateLiteral]: ts.TypeFlags.String,
} as const`
literalTypeFlags readonly [any, any, any, any, any] const `[
ts.TypeFlags.BigIntLiteral,
ts.TypeFlags.BooleanLiteral,
ts.TypeFlags.NumberLiteral,
ts.TypeFlags.StringLiteral,
ts.TypeFlags.TemplateLiteral,
] as const`
primitiveTypeFlags readonly [any, any, any, any] const `[
ts.TypeFlags.BigInt,
ts.TypeFlags.Boolean,
ts.TypeFlags.Number,
ts.TypeFlags.String,
] as const`
primitiveTypeFlagNames { readonly [x: number]: "string" | "number" | "bigint" | "boolean"; } const `{
[ts.TypeFlags.BigInt]: 'bigint',
[ts.TypeFlags.Boolean]: 'boolean',
[ts.TypeFlags.Number]: 'number',
[ts.TypeFlags.String]: 'string',
} as const`
primitiveTypeFlagTypes { readonly bigint: any; readonly boolean: any; readonly number: any; readonly string: any; } const `{
bigint: ts.TypeFlags.BigIntLiteral,
boolean: ts.TypeFlags.BooleanLiteral,
number: ts.TypeFlags.NumberLiteral,
string: ts.TypeFlags.StringLiteral,
} as const`
keywordNodeTypesToTsTypes Map<any, any> const `new Map([
[TSESTree.AST_NODE_TYPES.TSAnyKeyword, ts.TypeFlags.Any],
[TSESTree.AST_NODE_TYPES.TSBigIntKeyword, ts.TypeFlags.BigInt],
[TSESTree.AST_NODE_TYPES.TSBooleanKeyword, ts.TypeFlags.Boolean],
[TSESTree.AST_NODE_TYPES.TSNeverKeyword, ts.TypeFlags.Never],
[TSESTree.AST_NODE_TYPES.TSNumberKeyword, ts.TypeFlags.Number],
[TSESTree.AST_NODE_TYPES.TSStringKeyword, ts.TypeFlags.String],
[TSESTree.AST_NODE_TYPES.TSUnknownKeyword, ts.TypeFlags.Unknown],
])`
typesCache Map<TSESTree.TypeNode, TypeFlagsWithName[]> const new Map<TSESTree.TypeNode, TypeFlagsWithName[]>()
seenLiteralTypes Map<any, string[]> const new Map<PrimitiveTypeFlag, string[]>()
seenPrimitiveTypes Map<any, TSESTree.TypeNode[]> const `new Map<
PrimitiveTypeFlag,
TSESTree.TypeNode[]
>()`
seenUnionTypes Map<TSESTree.TypeNode, TypeFlagsWithName[]> const `new Map<
TSESTree.TypeNode,
TypeFlagsWithName[]
>()`
primitive number | undefined let/var undefined
seenLiteralTypes Map<any, TypeNodeWithValue[]> const `new Map<
PrimitiveTypeFlag,
TypeNodeWithValue[]
>()`
seenPrimitiveTypes Set<any> const new Set<PrimitiveTypeFlag>()
overriddenTypeNodes Map<TSESTree.TypeNode, TypeFlagWithText[]> const `new Map<
TSESTree.TypeNode,
TypeFlagWithText[]
>()`

Functions

addToMapGroup(map: Map<Key, Value[]>, key: Key, value: Value): void

Code
function addToMapGroup<Key, Value>(
  map: Map<Key, Value[]>,
  key: Key,
  value: Value,
): void {
  const existing = map.get(key);

  if (existing) {
    existing.push(value);
  } else {
    map.set(key, [value]);
  }
}
  • Parameters:
  • map: Map<Key, Value[]>
  • key: Key
  • value: Value
  • Return Type: void
  • Calls:
  • map.get
  • existing.push
  • map.set

describeLiteralType(type: ts.Type): string

Code
function describeLiteralType(type: ts.Type): string {
  if (type.isStringLiteral()) {
    return JSON.stringify(type.value);
  }

  if (isTypeBigIntLiteralType(type)) {
    return `${type.value.negative ? '-' : ''}${type.value.base10Value}n`;
  }

  if (type.isLiteral()) {
    // eslint-disable-next-line @typescript-eslint/no-base-to-string
    return type.value.toString();
  }

  if (tsutils.isIntrinsicErrorType(type) && type.aliasSymbol) {
    return type.aliasSymbol.escapedName.toString();
  }

  if (isTypeAnyType(type)) {
    return 'any';
  }

  if (isTypeNeverType(type)) {
    return 'never';
  }

  if (isTypeUnknownType(type)) {
    return 'unknown';
  }

  if (isTypeTemplateLiteralType(type)) {
    return 'template literal type';
  }

  if (isTypeBigIntLiteralType(type)) {
    return `${type.value.negative ? '-' : ''}${type.value.base10Value}n`;
  }

  if (tsutils.isTrueLiteralType(type)) {
    return 'true';
  }

  if (tsutils.isFalseLiteralType(type)) {
    return 'false';
  }

  return 'literal type';
}
  • Parameters:
  • type: ts.Type
  • Return Type: string
  • Calls:
  • type.isStringLiteral
  • JSON.stringify
  • isTypeBigIntLiteralType (from ../util)
  • type.isLiteral
  • type.value.toString
  • tsutils.isIntrinsicErrorType
  • type.aliasSymbol.escapedName.toString
  • isTypeAnyType (from ../util)
  • isTypeNeverType (from ../util)
  • isTypeUnknownType (from ../util)
  • isTypeTemplateLiteralType (from ../util)
  • tsutils.isTrueLiteralType
  • tsutils.isFalseLiteralType
  • Internal Comments:
    // eslint-disable-next-line @typescript-eslint/no-base-to-string
    

describeLiteralTypeNode(typeNode: TSESTree.TypeNode): string

Code
function describeLiteralTypeNode(typeNode: TSESTree.TypeNode): string {
  switch (typeNode.type) {
    case AST_NODE_TYPES.TSAnyKeyword:
      return 'any';
    case AST_NODE_TYPES.TSBooleanKeyword:
      return 'boolean';
    case AST_NODE_TYPES.TSNeverKeyword:
      return 'never';
    case AST_NODE_TYPES.TSNumberKeyword:
      return 'number';
    case AST_NODE_TYPES.TSStringKeyword:
      return 'string';
    case AST_NODE_TYPES.TSUnknownKeyword:
      return 'unknown';
    case AST_NODE_TYPES.TSLiteralType:
      switch (typeNode.literal.type) {
        case TSESTree.AST_NODE_TYPES.Literal:
          switch (typeof typeNode.literal.value) {
            case 'bigint':
              return `${typeNode.literal.value < 0 ? '-' : ''}${
                typeNode.literal.value
              }n`;
            case 'string':
              return JSON.stringify(typeNode.literal.value);
            default:
              return `${typeNode.literal.value}`;
          }
        case TSESTree.AST_NODE_TYPES.TemplateLiteral:
          return 'template literal type';
      }
  }

  return 'literal type';
}
  • Parameters:
  • typeNode: TSESTree.TypeNode
  • Return Type: string
  • Calls:
  • JSON.stringify

isNodeInsideReturnType(node: TSESTree.TSUnionType): boolean

Code
function isNodeInsideReturnType(node: TSESTree.TSUnionType): boolean {
  return (
    node.parent.type === AST_NODE_TYPES.TSTypeAnnotation &&
    isFunctionOrFunctionType(node.parent.parent)
  );
}
  • Parameters:
  • node: TSESTree.TSUnionType
  • Return Type: boolean
  • Calls:
  • isFunctionOrFunctionType (from ../util)

unionTypePartsUnlessBoolean(type: ts.Type): ts.Type[]

Code
function unionTypePartsUnlessBoolean(type: ts.Type): ts.Type[] {
  return type.isUnion() &&
    type.types.length === 2 &&
    tsutils.isFalseLiteralType(type.types[0]) &&
    tsutils.isTrueLiteralType(type.types[1])
    ? [type]
    : tsutils.unionConstituents(type);
}
  • JSDoc:

    /**
     * @remarks TypeScript stores boolean types as the union false | true, always.
     */
    

  • Parameters:

  • type: ts.Type
  • Return Type: ts.Type[]
  • Calls:
  • type.isUnion
  • tsutils.isFalseLiteralType
  • tsutils.isTrueLiteralType
  • tsutils.unionConstituents

getTypeNodeTypePartFlags(typeNode: TSESTree.TypeNode): TypeFlagsWithName[]

Code
function getTypeNodeTypePartFlags(
      typeNode: TSESTree.TypeNode,
    ): TypeFlagsWithName[] {
      const keywordTypeFlags = keywordNodeTypesToTsTypes.get(typeNode.type);
      if (keywordTypeFlags) {
        return [
          {
            typeFlags: keywordTypeFlags,
            typeName: describeLiteralTypeNode(typeNode),
          },
        ];
      }

      if (
        typeNode.type === AST_NODE_TYPES.TSLiteralType &&
        typeNode.literal.type === AST_NODE_TYPES.Literal
      ) {
        return [
          {
            typeFlags:
              primitiveTypeFlagTypes[
                typeof typeNode.literal
                  .value as keyof typeof primitiveTypeFlagTypes
              ],
            typeName: describeLiteralTypeNode(typeNode),
          },
        ];
      }

      if (typeNode.type === AST_NODE_TYPES.TSUnionType) {
        return typeNode.types.flatMap(getTypeNodeTypePartFlags);
      }

      const nodeType = services.getTypeAtLocation(typeNode);
      const typeParts = unionTypePartsUnlessBoolean(nodeType);

      return typeParts.map(typePart => ({
        typeFlags: typePart.flags,
        typeName: describeLiteralType(typePart),
      }));
    }
  • Parameters:
  • typeNode: TSESTree.TypeNode
  • Return Type: TypeFlagsWithName[]
  • Calls:
  • keywordNodeTypesToTsTypes.get
  • describeLiteralTypeNode
  • typeNode.types.flatMap
  • services.getTypeAtLocation
  • unionTypePartsUnlessBoolean
  • typeParts.map
  • describeLiteralType

getTypeNodeTypePartFlagsCached(typeNode: TSESTree.TypeNode): TypeFlagsWithName[]

Code
function getTypeNodeTypePartFlagsCached(
      typeNode: TSESTree.TypeNode,
    ): TypeFlagsWithName[] {
      const existing = typesCache.get(typeNode);
      if (existing) {
        return existing;
      }

      const created = getTypeNodeTypePartFlags(typeNode);
      typesCache.set(typeNode, created);
      return created;
    }
  • Parameters:
  • typeNode: TSESTree.TypeNode
  • Return Type: TypeFlagsWithName[]
  • Calls:
  • typesCache.get
  • getTypeNodeTypePartFlags
  • typesCache.set

checkIntersectionBottomAndTopTypes({ typeFlags, typeName }: TypeFlagsWithName, typeNode: TSESTree.TypeNode): boolean

Code
function checkIntersectionBottomAndTopTypes(
          { typeFlags, typeName }: TypeFlagsWithName,
          typeNode: TSESTree.TypeNode,
        ): boolean {
          for (const [messageId, checkFlag] of [
            ['overrides', ts.TypeFlags.Any],
            ['overrides', ts.TypeFlags.Never],
            ['overridden', ts.TypeFlags.Unknown],
          ] as const) {
            if (typeFlags === checkFlag) {
              context.report({
                node: typeNode,
                messageId:
                  typeFlags === ts.TypeFlags.Any && typeName !== 'any'
                    ? 'errorTypeOverrides'
                    : messageId,
                data: {
                  container: 'intersection',
                  typeName,
                },
              });
              return true;
            }
          }

          return false;
        }
  • Parameters:
  • { typeFlags, typeName }: TypeFlagsWithName
  • typeNode: TSESTree.TypeNode
  • Return Type: boolean
  • Calls:
  • context.report

checkIfUnionsAreAssignable(): undefined

Code
(): undefined => {
          for (const [typeRef, typeValues] of seenUnionTypes) {
            let primitive: number | undefined = undefined;
            for (const { typeFlags } of typeValues) {
              if (
                seenPrimitiveTypes.has(
                  literalToPrimitiveTypeFlags[
                    typeFlags as keyof typeof literalToPrimitiveTypeFlags
                  ],
                )
              ) {
                primitive =
                  literalToPrimitiveTypeFlags[
                    typeFlags as keyof typeof literalToPrimitiveTypeFlags
                  ];
              } else {
                primitive = undefined;
                break;
              }
            }
            if (Number.isInteger(primitive)) {
              context.report({
                node: typeRef,
                messageId: 'primitiveOverridden',
                data: {
                  literal: typeValues.map(name => name.typeName).join(' | '),
                  primitive:
                    primitiveTypeFlagNames[
                      primitive as keyof typeof primitiveTypeFlagNames
                    ],
                },
              });
            }
          }
        }
  • Return Type: undefined
  • Calls:
  • seenPrimitiveTypes.has
  • Number.isInteger
  • context.report
  • typeValues.map(name => name.typeName).join

checkUnionBottomAndTopTypes({ typeFlags, typeName }: TypeFlagsWithName, typeNode: TSESTree.TypeNode): boolean

Code
function checkUnionBottomAndTopTypes(
          { typeFlags, typeName }: TypeFlagsWithName,
          typeNode: TSESTree.TypeNode,
        ): boolean {
          for (const checkFlag of [
            ts.TypeFlags.Any,
            ts.TypeFlags.Unknown,
          ] as const) {
            if (typeFlags === checkFlag) {
              context.report({
                node: typeNode,
                messageId:
                  typeFlags === ts.TypeFlags.Any && typeName !== 'any'
                    ? 'errorTypeOverrides'
                    : 'overrides',
                data: {
                  container: 'union',
                  typeName,
                },
              });
              return true;
            }
          }

          if (
            typeFlags === ts.TypeFlags.Never &&
            !isNodeInsideReturnType(node)
          ) {
            context.report({
              node: typeNode,
              messageId: 'overridden',
              data: {
                container: 'union',
                typeName: 'never',
              },
            });
            return true;
          }

          return false;
        }
  • Parameters:
  • { typeFlags, typeName }: TypeFlagsWithName
  • typeNode: TSESTree.TypeNode
  • Return Type: boolean
  • Calls:
  • context.report
  • isNodeInsideReturnType

Interfaces

TypeFlagsWithName

Interface Code
interface TypeFlagsWithName {
  typeFlags: ts.TypeFlags;
  typeName: string;
}

Properties

Name Type Optional Description
typeFlags ts.TypeFlags
typeName string

TypeNodeWithValue

Interface Code
interface TypeNodeWithValue {
  literalValue: unknown;
  typeNode: TSESTree.TypeNode;
}

Properties

Name Type Optional Description
literalValue unknown
typeNode TSESTree.TypeNode

TypeFlagWithText

Interface Code
interface TypeFlagWithText {
          literalValue: unknown;
          primitiveTypeFlag: PrimitiveTypeFlag;
        }

Properties

Name Type Optional Description
literalValue unknown
primitiveTypeFlag PrimitiveTypeFlag

Type Aliases

PrimitiveTypeFlag

type PrimitiveTypeFlag = (typeof primitiveTypeFlags)[number];