Literal Types and Type Narrowing in TypeScript

TypeScript is a static typing language that offers valuable features to make the development process more robust and efficient. One such feature is literal types, which allow us to specify exact values for variables, object properties, and function parameters.

What are Literal Types?

In TypeScript, literal types can be defined for string, number, boolean, and even enum values. Instead of using generic types like string or number, literal types enable us to assign specific values directly to the variables. For example:

let name: "John";
let age: 25;
let isStudent: true;

By defining literal types, we restrict the variable to only hold a specific value. This can prevent various bugs that could occur due to accidental assignment of incorrect values, especially when working with complex business logic.

String Literal Types

String literal types allow us to specify the exact string value a variable can hold. For instance, instead of using the generic string type, we can narrow it down to something specific:

let color: "red" | "green" | "blue";

Here, the color variable can only be assigned one of the three specified values - "red", "green", or "blue". Any other string value assignment would result in a compilation error.

Number Literal Types

Similar to string literal types, number literal types enable us to restrict variable assignments to specific numeric values:

let evenNumber: 2 | 4 | 6 | 8;

Now, the evenNumber variable can only be assigned any of the specified even numbers. Assigning an odd number or any other value would be considered a type error.

Boolean Literal Types

Boolean literal types, as the name suggests, allow us to restrict a variable to only true or false values:

let isAdmin: true;

By defining isAdmin as true, we ensure that it can only hold the value true and not false or any other value.

Type Narrowing with Literal Types

Literal types bring significant advantages when it comes to type narrowing and improving type safety. Type narrowing is the ability of TypeScript to automatically refine the type of a variable based on certain conditions or operations.

For example, consider the following code snippet:

type PaymentMethod = "creditCard" | "bankTransfer";

function processPayment(method: PaymentMethod) {
  if (method === "creditCard") {
    // Type narrowing - method is now of type "creditCard"
    // Perform credit card processing logic
  } else if (method === "bankTransfer") {
    // Type narrowing - method is now of type "bankTransfer"
    // Perform bank transfer processing logic
  } else {
    // TypeScript detects that method can't be any other value
    // Compilation error: Argument of type 'string' is not assignable to parameter of type 'PaymentMethod'

In the above example, the function processPayment takes method as an argument with a literal type "creditCard" or "bankTransfer". Based on value comparison, TypeScript narrows the type of method within each conditional block, allowing us to perform specific operations without having to manually cast the type.

This powerful feature improves both code readability and reliability, as TypeScript helps catch potential issues at compile-time, ensuring type correctness.


Literal types and type narrowing are crucial features in TypeScript that assist in achieving type safety and preventing bugs related to incorrect value assignments. By precisely defining the allowed values, we can make the code more expressive and less prone to errors. Additionally, type narrowing enhances code readability and enables TypeScript to provide more accurate static analysis, ultimately leading to more efficient and reliable software development.

noob to master © copyleft