As a TypeScript developer, I got a requirement to compare a string to an enum in TypeScript. I’ve encountered this situation countless times in my projects.
In this tutorial, I’ll walk you through five different methods to compare strings with enums in TypeScript, each with its own advantages and use cases. Let’s dive in!
Understanding TypeScript Enums
Before we get into the comparison techniques, let’s quickly refresh our understanding of enums in TypeScript.
Enums in TypeScript allow us to define a set of named constants, making our code more readable and self-documenting. TypeScript supports two primary types of enums:
- Numeric enums – Where members are assigned incremental numeric values
- String enums – Where each member has an explicit string value
Here’s a simple example of both types:
// Numeric enum
enum UserRole {
Admin, // 0
Editor, // 1
Viewer // 2
}
// String enum
enum PaymentStatus {
Pending = "PENDING",
Completed = "COMPLETED",
Failed = "FAILED"
}
Now, let’s look at how to compare strings to these enum types.
Check out How to Iterate Over Enums in TypeScript?
Method 1: Using Type Assertion
The best approach is to use TypeScript’s type assertion to convert a string to an enum value:
enum PaymentStatus {
Pending = "PENDING",
Completed = "COMPLETED",
Failed = "FAILED"
}
function processPayment(status: string): void {
// Convert string to enum using type assertion
const paymentStatus = status as unknown as PaymentStatus;
if (paymentStatus === PaymentStatus.Completed) {
console.log("Payment was successful!");
} else if (paymentStatus === PaymentStatus.Failed) {
console.log("Payment failed. Please try again.");
} else if (paymentStatus === PaymentStatus.Pending) {
console.log("Payment is being processed...");
} else {
console.log("Unknown payment status");
}
}
// Example usage
processPayment("COMPLETED"); // Output: Payment was successful!
While this method is simple, it lacks type safety. The string could be anything, and TypeScript won’t catch invalid values at compile time.
You can see the exact output in the screenshot below:

Read Convert String to Enum in TypeScript
Method 2: Using String Enum Keys
A more type-safe approach is to check if the string matches any of the enum’s values:
enum OrderStatus {
New = "NEW",
Processing = "PROCESSING",
Shipped = "SHIPPED",
Delivered = "DELIVERED",
Canceled = "CANCELED"
}
function isValidOrderStatus(status: string): boolean {
return Object.values(OrderStatus).includes(status as any);
}
function updateOrderStatus(orderId: string, newStatus: string): void {
if (isValidOrderStatus(newStatus)) {
// Safe to use the string as an enum value
const orderStatus = newStatus as OrderStatus;
console.log(`Order ${orderId} updated to: ${orderStatus}`);
} else {
console.error(`Invalid order status: ${newStatus}`);
}
}
// Example usage
updateOrderStatus("ORD-1234", "SHIPPED"); // Valid
updateOrderStatus("ORD-5678", "UNKNOWN"); // Invalid
This method validates the string before using it as an enum value, providing better safety.
You can see the output in the screenshot below:

Check out Check If a String Is in an Enum in TypeScript
Method 3: Using a Type Guard Function
Type guards in TypeScript can help us create a more elegant solution:
enum TaxFilingStatus {
Single = "SINGLE",
MarriedJoint = "MARRIED_JOINT",
MarriedSeparate = "MARRIED_SEPARATE",
HeadOfHousehold = "HEAD_OF_HOUSEHOLD"
}
// Type guard function
function isTaxFilingStatus(value: string): value is TaxFilingStatus {
return Object.values(TaxFilingStatus).includes(value as any);
}
function calculateTaxRate(income: number, status: string): number {
if (isTaxFilingStatus(status)) {
// TypeScript now knows status is a valid TaxFilingStatus
switch (status) {
case TaxFilingStatus.Single:
return income * 0.24;
case TaxFilingStatus.MarriedJoint:
return income * 0.22;
case TaxFilingStatus.MarriedSeparate:
return income * 0.24;
case TaxFilingStatus.HeadOfHousehold:
return income * 0.20;
}
} else {
console.error(`Invalid tax filing status: ${status}`);
return 0;
}
}
// Example usage
const taxAmount = calculateTaxRate(75000, "SINGLE");
console.log(`Tax amount: $${taxAmount}`); // Tax amount: $18000
The type guard function tells TypeScript that if the check passes, the string is definitely a valid enum value. This gives us excellent type safety and editor support.
Check out Convert TypeScript Enums to Arrays
Method 4: Using Enum Reverse Mapping for Numeric Enums
For numeric enums, TypeScript creates a reverse mapping, which can be useful for string comparisons:
enum StateCode {
California = 1,
Texas = 2,
Florida = 3,
NewYork = 4
}
function getStateNameFromString(stateStr: string): string {
// Convert string to number if it's numeric
const stateNum = parseInt(stateStr, 10);
// Check if it's a valid numeric code
if (!isNaN(stateNum) && StateCode[stateNum]) {
return StateCode[stateNum];
}
// Check if it's a valid state name
const stateIndex = Object.keys(StateCode).indexOf(stateStr);
if (stateIndex !== -1) {
const numericValue = Object.values(StateCode)[stateIndex];
return StateCode[numericValue as number];
}
return "Unknown State";
}
// Example usage
console.log(getStateNameFromString("2")); // Output: Texas
console.log(getStateNameFromString("Texas")); // Output: Texas
console.log(getStateNameFromString("Oregon")); // Output: Unknown State
This method works great with numeric enums due to TypeScript’s reverse mapping feature.
Read TypeScript Enum Reverse Mapping
Method 5: Using a Map for Enhanced Performance
For applications where performance is critical or you’re comparing strings to enums frequently, using a Map can be more efficient:
enum CreditCardType {
Visa = "VISA",
Mastercard = "MASTERCARD",
Amex = "AMERICAN_EXPRESS",
Discover = "DISCOVER"
}
// Create a map for fast lookups
const cardTypeMap = new Map<string, CreditCardType>([
["VISA", CreditCardType.Visa],
["MASTERCARD", CreditCardType.Mastercard],
["AMERICAN_EXPRESS", CreditCardType.Amex],
["DISCOVER", CreditCardType.Discover],
// Add common variations
["VISA CARD", CreditCardType.Visa],
["MASTER CARD", CreditCardType.Mastercard],
["AMEX", CreditCardType.Amex]
]);
function validateCreditCard(cardNumber: string, cardTypeStr: string): boolean {
// Normalize the input string
const normalizedType = cardTypeStr.toUpperCase().trim();
// Check if it's a valid card type
if (cardTypeMap.has(normalizedType)) {
const cardType = cardTypeMap.get(normalizedType);
console.log(`Processing ${cardType} card: ${cardNumber}`);
// Perform card-specific validation logic here
switch (cardType) {
case CreditCardType.Visa:
return /^4[0-9]{12}(?:[0-9]{3})?$/.test(cardNumber);
case CreditCardType.Mastercard:
return /^5[1-5][0-9]{14}$/.test(cardNumber);
case CreditCardType.Amex:
return /^3[47][0-9]{13}$/.test(cardNumber);
case CreditCardType.Discover:
return /^6(?:011|5[0-9]{2})[0-9]{12}$/.test(cardNumber);
}
}
console.error(`Unsupported card type: ${cardTypeStr}`);
return false;
}
// Example usage
validateCreditCard("4111111111111111", "Visa"); // Valid Visa card
validateCreditCard("378282246310005", "amex"); // Valid Amex card
This approach is particularly useful when you need to handle variations of string inputs that should map to the same enum value.
Check out Check If a Value Is in an Enum in TypeScript
Best Practices When Comparing Strings to Enums
Based on my experience, here are some best practices to follow:
- Normalize string inputs – Convert to uppercase/lowercase and trim whitespace before comparison
- Validate before converting – Always check if a string is a valid enum value before treating it as one
- Use type guards – They provide the best combination of runtime safety and TypeScript type inference
- Consider performance – For frequent comparisons, use Maps or lookup objects
- Handle unknown values – Always have a fallback for when the string doesn’t match any enum value
Real-World Example: E-commerce Order Processing
Let’s see how we might use string-to-enum comparison in a real e-commerce order processing system:
enum OrderStatus {
New = "NEW",
Processing = "PROCESSING",
Shipped = "SHIPPED",
Delivered = "DELIVERED",
Canceled = "CANCELED",
Returned = "RETURNED"
}
// Type guard for OrderStatus
function isOrderStatus(value: string): value is OrderStatus {
return Object.values(OrderStatus).includes(value as any);
}
class Order {
id: string;
status: OrderStatus;
constructor(id: string, initialStatus: OrderStatus = OrderStatus.New) {
this.id = id;
this.status = initialStatus;
}
updateStatus(newStatusStr: string): boolean {
// Normalize the status string
const normalizedStatus = newStatusStr.toUpperCase().trim();
// Validate and convert the string to enum
if (isOrderStatus(normalizedStatus)) {
// Apply business rules
if (this.status === OrderStatus.Canceled && normalizedStatus !== OrderStatus.Returned) {
console.error("Cannot change status after cancellation except to Returned");
return false;
}
if (this.status === OrderStatus.Delivered &&
normalizedStatus !== OrderStatus.Returned &&
normalizedStatus !== OrderStatus.Canceled) {
console.error("Delivered orders can only be Returned or Canceled");
return false;
}
// Update status
this.status = normalizedStatus;
console.log(`Order ${this.id} updated to: ${this.status}`);
return true;
} else {
console.error(`Invalid order status: ${newStatusStr}`);
return false;
}
}
}
// Example usage
const order = new Order("ORD-12345");
order.updateStatus("processing"); // Works, case insensitive
order.updateStatus("SHIPPED"); // Works
order.updateStatus("DELIVERED"); // Works
order.updateStatus("REFUNDED"); // Error: Invalid order status
This example demonstrates how we can build a robust system with proper type safety when comparing string inputs to enum values. The Order class handles validation, normalization, and business rules while maintaining type safety throughout the codebase.
Check out TypeScript Switch with Enums
Working with External APIs and User Input
When building real applications, we often need to compare string values from external sources (like API responses or user input) to our TypeScript enums. Here’s how to handle this safely:
enum USState {
Alabama = "AL",
Alaska = "AK",
Arizona = "AZ",
// ... other states
Wyoming = "WY"
}
// Create a reverse lookup for state codes and full names
const statesByCode: Record<string, USState> = {};
const statesByName: Record<string, USState> = {};
// Populate lookup tables
Object.entries(USState).forEach(([name, code]) => {
statesByCode[code] = code as USState;
statesByName[name.toLowerCase()] = code as USState;
});
function getStateEnum(stateInput: string): USState | null {
const normalized = stateInput.trim();
// Check if it's a valid state code (e.g., "CA")
if (normalized.length <= 2 && statesByCode[normalized.toUpperCase()]) {
return statesByCode[normalized.toUpperCase()];
}
// Check if it's a valid state name (e.g., "California")
if (statesByName[normalized.toLowerCase()]) {
return statesByName[normalized.toLowerCase()];
}
// Not found
return null;
}
// Example: Processing a shipping address form
function validateShippingAddress(address: {
street: string;
city: string;
state: string;
zip: string;
}): boolean {
const stateEnum = getStateEnum(address.state);
if (!stateEnum) {
console.error(`Invalid state: ${address.state}`);
return false;
}
console.log(`Shipping to ${address.city}, ${stateEnum}`);
// Perform state-specific validation
switch (stateEnum) {
case USState.Alaska:
case USState.Hawaii:
console.log("Additional shipping fees may apply");
break;
case USState.California:
console.log("Checking California-specific tax regulations");
break;
}
return true;
}
// Example usage
validateShippingAddress({
street: "123 Main St",
city: "San Francisco",
state: "California", // Works with full name
zip: "94105"
});
validateShippingAddress({
street: "456 Broadway",
city: "New York",
state: "NY", // Works with state code
zip: "10001"
});
This approach provides flexibility while maintaining type safety when dealing with user input or API data.
Read How to Convert Enums to Strings in TypeScript?
Performance Considerations
When working with large enums or in performance-critical sections of your application, the method you choose for string-to-enum comparison can make a significant difference:
enum ProductCategory {
Electronics = "ELECTRONICS",
Clothing = "CLOTHING",
Furniture = "FURNITURE",
Books = "BOOKS",
Groceries = "GROCERIES",
// ... many more categories
}
// Benchmarking different approaches
function benchmarkStringEnumComparison(iterations: number): void {
const testString = "ELECTRONICS";
console.time("Direct comparison");
for (let i = 0; i < iterations; i++) {
const result = testString === ProductCategory.Electronics;
}
console.timeEnd("Direct comparison");
console.time("Object.values lookup");
for (let i = 0; i < iterations; i++) {
const result = Object.values(ProductCategory).includes(testString as any);
}
console.timeEnd("Object.values lookup");
// Create a Set for faster lookups
const categorySet = new Set(Object.values(ProductCategory));
console.time("Set lookup");
for (let i = 0; i < iterations; i++) {
const result = categorySet.has(testString as any);
}
console.timeEnd("Set lookup");
}
// Run benchmark with 1 million iterations
benchmarkStringEnumComparison(1000000);
In my tests, the Set-based lookup typically outperforms Object.values().includes() for larger enums, while direct comparison is always fastest when you already know the enum value you’re comparing against.
Conclusion
In this tutorial, I explained how to compare strings to enums in TypeScript using several methods. For simple scenarios, type guards and validation functions work well. For performance-critical code or complex mapping requirements, consider using Maps or specialized lookup structures.
Do let me know in the comments below if these real examples help you.
You may also like:

Hey! I’m Bijay Kumar, founder of SPGuides.com and a Microsoft Business Applications MVP (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and training videos. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.