📄 enum-utils/shared¶
📊 Analysis Summary¶
| Metric | Count |
|---|---|
| 🔧 Functions | 7 |
| 📦 Imports | 3 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/eslint-plugin/src/rules/enum-utils/shared.ts
📦 Imports¶
| Name | Source |
|---|---|
isNumberLike |
../../util |
isStringLike |
../../util |
isTypeFlagSet |
../../util |
Functions¶
getEnumLiterals(type: ts.Type): ts.LiteralType[]¶
Retrieve only the Enum literals from a type. for example: - 123 --> [] - {} --> [] - Fruit.Apple --> [Fruit.Apple] - Fruit.Apple | Vegetable.Lettuce --> [Fruit.Apple, Vegetable.Lettuce] - Fruit.Apple | Vegetable.Lettuce | 123 --> [Fruit.Apple, Vegetable.Lettuce] - T extends Fruit --> [Fruit]
Raw JSDoc
/**
* Retrieve only the Enum literals from a type. for example:
* - 123 --> []
* - {} --> []
* - Fruit.Apple --> [Fruit.Apple]
* - Fruit.Apple | Vegetable.Lettuce --> [Fruit.Apple, Vegetable.Lettuce]
* - Fruit.Apple | Vegetable.Lettuce | 123 --> [Fruit.Apple, Vegetable.Lettuce]
* - T extends Fruit --> [Fruit]
*/
Calls:
tsutils .unionConstituents(type) .filterisTypeFlagSet (from ../../util)
Code
getEnumTypes(typeChecker: ts.TypeChecker, type: ts.Type): ts.Type[]¶
A type can have 0 or more enum types. For example: - 123 --> [] - {} --> [] - Fruit.Apple --> [Fruit] - Fruit.Apple | Vegetable.Lettuce --> [Fruit, Vegetable] - Fruit.Apple | Vegetable.Lettuce | 123 --> [Fruit, Vegetable] - T extends Fruit --> [Fruit]
Raw JSDoc
Calls:
getEnumLiterals(type).mapgetBaseEnumType
Code
isMismatchedEnumComparisonTypes(typeChecker: ts.TypeChecker, leftType: ts.Type, rightType: ts.Type): boolean¶
Returns: undefined
Whether two types compare unsafely because an enum value is being
compared against a non-enum value of the same primitive kind.
Raw JSDoc
Calls:
getEnumTypesrightEnumTypes.hastsutils.unionConstituentsrightTypeParts.includestypeViolates
Internal Comments:
// Allow comparisons that don't have anything to do with enums: (x2)
// (x6)
// ```ts (x6)
// 1 === 2; (x2)
// ``` (x6)
// Allow comparisons that share an enum type:
// Fruit.Apple === Fruit.Banana;
// We need to split the type into the union type parts in order to find (x2)
// valid enum comparisons like: (x2)
// declare const something: Fruit | Vegetable; (x2)
// something === Fruit.Apple; (x2)
// If a type exists in both sides, we consider this comparison safe:
// declare const fruit: Fruit.Apple | 0;
// fruit === 0;
Code
export function isMismatchedEnumComparisonTypes(
typeChecker: ts.TypeChecker,
leftType: ts.Type,
rightType: ts.Type,
): boolean {
// Allow comparisons that don't have anything to do with enums:
//
// ```ts
// 1 === 2;
// ```
const leftEnumTypes = getEnumTypes(typeChecker, leftType);
const rightEnumTypes = new Set(getEnumTypes(typeChecker, rightType));
if (leftEnumTypes.length === 0 && rightEnumTypes.size === 0) {
return false;
}
// Allow comparisons that share an enum type:
//
// ```ts
// Fruit.Apple === Fruit.Banana;
// ```
for (const leftEnumType of leftEnumTypes) {
if (rightEnumTypes.has(leftEnumType)) {
return false;
}
}
// We need to split the type into the union type parts in order to find
// valid enum comparisons like:
//
// ```ts
// declare const something: Fruit | Vegetable;
// something === Fruit.Apple;
// ```
const leftTypeParts = tsutils.unionConstituents(leftType);
const rightTypeParts = tsutils.unionConstituents(rightType);
// If a type exists in both sides, we consider this comparison safe:
//
// ```ts
// declare const fruit: Fruit.Apple | 0;
// fruit === 0;
// ```
for (const leftTypePart of leftTypeParts) {
if (rightTypeParts.includes(leftTypePart)) {
return false;
}
}
return (
typeViolates(leftTypeParts, rightType) ||
typeViolates(rightTypeParts, leftType)
);
}
getEnumKeyForLiteral(enumLiterals: ts.LiteralType[], literal: unknown): string | null¶
Returns the enum key that matches the given literal node, or null if none match. For example:
enum Fruit {
Apple = 'apple',
Banana = 'banana',
}
getEnumKeyForLiteral([Fruit.Apple, Fruit.Banana], 'apple') --> 'Fruit.Apple'
getEnumKeyForLiteral([Fruit.Apple, Fruit.Banana], 'banana') --> 'Fruit.Banana'
getEnumKeyForLiteral([Fruit.Apple, Fruit.Banana], 'cherry') --> null
Raw JSDoc
/**
* Returns the enum key that matches the given literal node, or null if none
* match. For example:
* ```ts
* enum Fruit {
* Apple = 'apple',
* Banana = 'banana',
* }
*
* getEnumKeyForLiteral([Fruit.Apple, Fruit.Banana], 'apple') --> 'Fruit.Apple'
* getEnumKeyForLiteral([Fruit.Apple, Fruit.Banana], 'banana') --> 'Fruit.Banana'
* getEnumKeyForLiteral([Fruit.Apple, Fruit.Banana], 'cherry') --> null
* ```
*/
Calls:
memberNameIdentifier.text.replaceAllmemberNameIdentifier.expression.getText
Code
export function getEnumKeyForLiteral(
enumLiterals: ts.LiteralType[],
literal: unknown,
): string | null {
for (const enumLiteral of enumLiterals) {
if (enumLiteral.value === literal) {
const { symbol } = enumLiteral;
const memberDeclaration = symbol.valueDeclaration as ts.EnumMember;
const enumDeclaration = memberDeclaration.parent;
const memberNameIdentifier = memberDeclaration.name;
const enumName = enumDeclaration.name.text;
switch (memberNameIdentifier.kind) {
case ts.SyntaxKind.Identifier:
return `${enumName}.${memberNameIdentifier.text}`;
case ts.SyntaxKind.StringLiteral: {
const memberName = memberNameIdentifier.text.replaceAll("'", "\\'");
return `${enumName}['${memberName}']`;
}
case ts.SyntaxKind.ComputedPropertyName:
return `${enumName}[${memberNameIdentifier.expression.getText()}]`;
default:
break;
}
}
}
return null;
}
getBaseEnumType(typeChecker: ts.TypeChecker, type: ts.Type): ts.Type¶
Parameters:
typeCheckerts.TypeCheckertypets.Type
Returns: ts.Type
Calls:
type.getSymboltsutils.isSymbolFlagSettypeChecker.getTypeAtLocation
Internal Comments:
Code
function getBaseEnumType(typeChecker: ts.TypeChecker, type: ts.Type): ts.Type {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const symbol = type.getSymbol()!;
if (!tsutils.isSymbolFlagSet(symbol, ts.SymbolFlags.EnumMember)) {
return type;
}
return typeChecker.getTypeAtLocation(
(symbol.valueDeclaration as ts.EnumMember).parent,
);
}
typeViolates(leftTypeParts: ts.Type[], rightType: ts.Type): boolean¶
Returns: undefined
Whether the right type is an unsafe comparison against any left type.
Calls:
leftTypeParts.mapleftEnumValueTypes.hasisNumberLike (from ../../util)isStringLike (from ../../util)
Code
function typeViolates(leftTypeParts: ts.Type[], rightType: ts.Type): boolean {
const leftEnumValueTypes = new Set(leftTypeParts.map(getEnumValueType));
return (
(leftEnumValueTypes.has(ts.TypeFlags.Number) && isNumberLike(rightType)) ||
(leftEnumValueTypes.has(ts.TypeFlags.String) && isStringLike(rightType))
);
}
getEnumValueType(type: ts.Type): ts.TypeFlags | undefined¶
Returns: undefined
What type a type's enum value is (number or string), if either.
Calls:
tsutils.isTypeFlagSet
Code
Generated by Syntax Scribe