Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding TypeScript's Special Types: any, unknown, void, and never

Tech 2

The any Type

The any type instructs the TypeScript compiler to bypass static type checking.

  • Variables of type any can be reassigned to values of any other type.
  • You can call arbitrary methods or access properties on an any value with out compile-time errors.
  • The any type is assignable to any other type.
  • If a variable is declared without a type annotation or initial value, TypeScript infers it as any.
let dynamicValue: any = 123;
dynamicValue = 'a string value';
dynamicValue = { prop: 'value' };

// Assigning an `any` value to a strictly typed variable
let numericValue: number = dynamicValue;
console.log(numericValue);

Using any eliminates the benefits of TypeScript's static type safety, similar to writing plain JavaScript.

The unknown Type

The unknown type represents a value whose type is not yet known, providing a type-safe alternative to any.

  • An unknown variable can be assigned a value of any type.
  • However, you cannot perform operations on an unknown value or assign it to a variable of a different type (except any or another unknown`) without first narrowing its type.
  • Type narrowing can be achieved through type guards, assertions, or control flow analysis.
let uncertainValue: unknown;
uncertainValue = 100;
uncertainValue = false;
uncertainValue = { data: 'test' };

// Valid assignments
let anotherUnknown: unknown = uncertainValue;
let anAnyValue: any = uncertainValue;

// Invalid assignment - causes a compile error
// let isReady: boolean = uncertainValue; // Error

To safely use a unknown value, you must first narrow its type.

function safelyProcess(value: unknown) {
  if (typeof value === 'string') {
    // Within this block, `value` is type `string`
    console.log(value.toUpperCase());
  }
  if (value instanceof Date) {
    // Here, `value` is type `Date`
    console.log(value.getFullYear());
  }
}

A type assertion can also be used to direct the compiler, but this requires confidence in the runtime type.

let userInput: unknown = fetchInput();
let textLength: number = (userInput as string).length;

The void Type

The void type signifies the absence of a value, typically used as the return type for funcsions that do not return a value.

function logMessage(msg: string): void {
  console.log(`Log: ${msg}`);
  // No return statement needed, or `return;` / `return undefined;`
}

When used for a variable, a void type can only be assigned undefined or null (with strictNullChecks disabled).

let noReturnValue: void = undefined;
// let invalidAssignment: void = 10; // Compilation error

The never Type

The never type represents values that never occur. It is used for functions that never return normally or for variables that cannot have a value.

  • never is a subtype of every other type, meaning a never value can be assigned to any variable.
  • No other type (except never itself) is a subtype of never. You cannot assign any other value (including any) to a never variable.
  • Common use cases include functions that always throw an error or contain an infinite loop.
// Function that always throws an error
function reportFatalError(message: string): never {
  throw new Error(`Fatal: ${message}`);
}

// Function with an infinite loop
function runIndefinitely(): never {
  while (true) {
    // Perform an ongoing task
  }
}

// Example of exhaustive checking in a union type
type Shape = 
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; side: number };

function calculateArea(s: Shape): number {
  switch (s.kind) {
    case 'circle':
      return Math.PI * s.radius ** 2;
    case 'square':
      return s.side ** 2;
    default:
      // `s` has type `never` here, ensuring all cases are handled
      const exhaustiveCheck: never = s;
      return exhaustiveCheck;
  }
}

Declaring a variable of type never is possible but it cannot be assigned any value.

let impossibleState: never;
// impossibleState = 123; // Compilation error
// impossibleState = null; // Compilation error

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.