Skip to main content
Type guard that checks whether a value is a CallData instance. Provides TypeScript type narrowing.

Signature

function is(value: unknown): value is CallDataType

Parameters

  • value - Value to check (any type)

Returns

boolean - true if value is CallData instance (with type narrowing)

Examples

import { CallData, type CallDataType } from '@tevm/voltaire';

const value: unknown = someFunction();

if (CallData.is(value)) {
  // value is CallDataType here (type narrowed)
  const selector = CallData.getSelector(value);
  console.log(selector);
}

Type Narrowing

TypeScript narrows the type when is() returns true:
import { CallData, type CallDataType } from '@tevm/voltaire';

function handle(value: unknown) {
  // Before: value is unknown
  console.log(value.length); // ❌ Type error

  if (CallData.is(value)) {
    // After: value is CallDataType
    console.log(value.length); // ✅ OK
    console.log(CallData.toHex(value)); // ✅ OK
  }
}

Comparison with isValid

import { CallData, type CallDataType } from '@tevm/voltaire';

function process(value: unknown) {
  if (CallData.is(value)) {
    // value is CallDataType (type narrowed)
    return CallData.toHex(value); // Direct use
  }
}
Checks: Already constructed CallData instance Returns: Type guard (value is CallDataType) Use for: Type narrowing, checking existing instances

Use Cases

Function Overloads

import { CallData, type CallDataType } from '@tevm/voltaire';

function processData(data: string): CallDataType;
function processData(data: CallDataType): CallDataType;
function processData(data: string | CallDataType): CallDataType {
  if (CallData.is(data)) {
    return data; // Already CallData
  } else {
    return CallData(data); // Convert from string
  }
}

Union Type Handling

import { CallData, type CallDataType, type Bytecode } from '@tevm/voltaire';

function analyze(data: CallDataType | Bytecode) {
  if (CallData.is(data)) {
    // Handle as calldata
    const selector = CallData.getSelector(data);
    console.log("Function call:", selector);
  } else {
    // Handle as bytecode
    console.log("Contract code:", Bytecode.toHex(data));
  }
}

Generic Functions

import { CallData, type CallDataType } from '@tevm/voltaire';

function logIfCallData<T>(value: T): T {
  if (CallData.is(value)) {
    console.log("CallData:", CallData.toHex(value));
  }
  return value;
}

// Usage
const result = logIfCallData(someValue); // Type preserved

Type-Safe Caching

import { CallData, type CallDataType } from '@tevm/voltaire';

class Cache<T> {
  private data = new Map<string, T>();

  set(key: unknown, value: T): void {
    if (CallData.is(key)) {
      this.data.set(CallData.toHex(key), value);
    } else {
      throw new Error("Key must be CallData");
    }
  }

  get(key: unknown): T | undefined {
    if (CallData.is(key)) {
      return this.data.get(CallData.toHex(key));
    }
    return undefined;
  }
}

Implementation

Checks for CallData brand:
// Simplified implementation
import { brand } from './brand.js';

export function is(value: unknown): value is CallDataType {
  return (
    value instanceof Uint8Array &&
    (value as any)[brand] === "CallData" &&
    value.length >= 4
  );
}
Checks:
  1. Is Uint8Array
  2. Has CallData brand
  3. Minimum 4 bytes (selector)

Performance

Very fast (just property checks):
// Benchmark: 10M iterations
const calldata = CallData("0xa9059cbb");
const notCalldata = "0xa9059cbb";

console.time("is (calldata)");
for (let i = 0; i < 10_000_000; i++) {
  CallData.is(calldata);
}
console.timeEnd("is (calldata)");
// ~80ms

console.time("is (not calldata)");
for (let i = 0; i < 10_000_000; i++) {
  CallData.is(notCalldata);
}
console.timeEnd("is (not calldata)");
// ~30ms (fails fast)

Type Safety Example

import { CallData, type CallDataType } from '@tevm/voltaire';

// Function that requires CallData
function process(data: CallDataType) {
  return CallData.decode(data, abi);
}

// Safe wrapper with type guard
function safeProcess(data: unknown) {
  if (!CallData.is(data)) {
    throw new Error("Expected CallData");
  }

  return process(data); // Type-safe
}

Branded Type Pattern

CallData uses Symbol branding for type safety:
import { brand } from './brand.js';

// Type definition
export type CallDataType = Uint8Array & {
  readonly [brand]: "CallData";
};

// Runtime check
export function is(value: unknown): value is CallDataType {
  return (
    value instanceof Uint8Array &&
    (value as any)[brand] === "CallData"
  );
}
This prevents accidental mixing of Uint8Arrays with CallData.