CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sindresorhus--is

Type check values with comprehensive TypeScript type guards and runtime assertions

Pending
Overview
Eval results
Files

web-apis.mddocs/

Web APIs and DOM

Type checking for web-specific APIs including DOM elements, form data, URL objects, and browser-specific types.

Capabilities

HTML Element Checking

Check if a value is an HTML DOM element.

/**
 * Check if value is an HTML element
 * @param value - Value to check
 * @returns True if value is HTMLElement
 */
function isHtmlElement(value: unknown): value is HTMLElement;

Usage Examples:

import is from '@sindresorhus/is';

// DOM elements
const div = document.createElement('div');
const button = document.querySelector('button');
const body = document.body;

is.htmlElement(div); // => true
is.htmlElement(button); // => true (if found)
is.htmlElement(body); // => true

// Non-elements
is.htmlElement(document); // => false
is.htmlElement(window); // => false
is.htmlElement('div'); // => false

// Type guard usage
function attachEventListener(element: unknown, event: string, handler: Function) {
  if (is.htmlElement(element)) {
    // element is now typed as HTMLElement
    element.addEventListener(event, handler as EventListener);
    return () => element.removeEventListener(event, handler as EventListener);
  }
  throw new Error('Element must be an HTMLElement');
}

// DOM manipulation
function setElementContent(element: unknown, content: string) {
  if (is.htmlElement(element)) {
    element.textContent = content;
    element.style.display = 'block';
  }
}

Blob Type Checking

Check if a value is a Blob object.

/**
 * Check if value is a Blob
 * @param value - Value to check
 * @returns True if value is Blob
 */
function isBlob(value: unknown): value is Blob;

Usage Examples:

import is from '@sindresorhus/is';

// Creating blobs
const textBlob = new Blob(['Hello, World!'], { type: 'text/plain' });
const jsonBlob = new Blob([JSON.stringify({data: 'test'})], { type: 'application/json' });

is.blob(textBlob); // => true
is.blob(jsonBlob); // => true

// File objects (inherit from Blob)
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
const file = fileInput?.files?.[0];
if (file) {
  is.blob(file); // => true (File extends Blob)
}

// Type guard usage
async function processBlob(data: unknown) {
  if (is.blob(data)) {
    // data is now typed as Blob
    console.log('Blob size:', data.size);
    console.log('Blob type:', data.type);
    
    const text = await data.text();
    console.log('Blob content:', text);
  }
}

// File upload handling
function handleFileUpload(file: unknown) {
  if (is.blob(file)) {
    const formData = new FormData();
    formData.append('file', file);
    return formData;
  }
  throw new Error('Invalid file provided');
}

FormData Type Checking

Check if a value is a FormData object.

/**
 * Check if value is FormData
 * @param value - Value to check
 * @returns True if value is FormData
 */
function isFormData(value: unknown): value is FormData;

Usage Examples:

import is from '@sindresorhus/is';

const formData = new FormData();
formData.append('name', 'John');
formData.append('age', '30');

is.formData(formData); // => true
is.formData({}); // => false
is.formData(new URLSearchParams()); // => false

// Type guard usage
function submitForm(data: unknown) {
  if (is.formData(data)) {
    // data is now typed as FormData
    for (const [key, value] of data.entries()) {
      console.log(`${key}: ${value}`);
    }
    
    return fetch('/api/submit', {
      method: 'POST',
      body: data
    });
  }
  throw new Error('Data must be FormData');
}

// Form processing
function processFormSubmission(form: HTMLFormElement, additionalData: Record<string, string>) {
  const formData = new FormData(form);
  
  // Add additional data
  Object.entries(additionalData).forEach(([key, value]) => {
    formData.append(key, value);
  });
  
  if (is.formData(formData)) {
    return submitForm(formData);
  }
}

URL Instance Checking

Check if a value is a URL object instance.

/**
 * Check if value is a URL instance
 * @param value - Value to check
 * @returns True if value is URL instance
 */
function isUrlInstance(value: unknown): value is URL;

Usage Examples:

import is from '@sindresorhus/is';

const url = new URL('https://example.com/path?query=value');
const invalidUrl = 'https://example.com';

is.urlInstance(url); // => true
is.urlInstance(invalidUrl); // => false (string, not URL instance)

// Type guard usage
function processUrl(url: unknown) {
  if (is.urlInstance(url)) {
    // url is now typed as URL
    console.log('Protocol:', url.protocol);
    console.log('Host:', url.host);
    console.log('Pathname:', url.pathname);
    console.log('Search params:', url.searchParams.toString());
    
    return {
      protocol: url.protocol,
      host: url.host,
      path: url.pathname,
      query: Object.fromEntries(url.searchParams)
    };
  }
  throw new Error('Invalid URL instance');
}

// URL manipulation
function addQueryParams(url: unknown, params: Record<string, string>) {
  if (is.urlInstance(url)) {
    Object.entries(params).forEach(([key, value]) => {
      url.searchParams.set(key, value);
    });
    return url.toString();
  }
  throw new Error('URL must be a URL instance');
}

URLSearchParams Type Checking

Check if a value is a URLSearchParams object.

/**
 * Check if value is URLSearchParams
 * @param value - Value to check
 * @returns True if value is URLSearchParams
 */
function isUrlSearchParams(value: unknown): value is URLSearchParams;

Usage Examples:

import is from '@sindresorhus/is';

const params = new URLSearchParams('?name=John&age=30');
const paramsFromObject = new URLSearchParams({ city: 'NYC', country: 'US' });

is.urlSearchParams(params); // => true
is.urlSearchParams(paramsFromObject); // => true
is.urlSearchParams('?name=John&age=30'); // => false (string)

// Type guard usage
function processSearchParams(params: unknown) {
  if (is.urlSearchParams(params)) {
    // params is now typed as URLSearchParams
    const result: Record<string, string> = {};
    
    for (const [key, value] of params.entries()) {
      result[key] = value;
    }
    
    return result;
  }
  throw new Error('Invalid URLSearchParams');
}

// Query string manipulation
function buildQueryString(params: unknown, additionalParams: Record<string, string>) {
  let searchParams: URLSearchParams;
  
  if (is.urlSearchParams(params)) {
    searchParams = new URLSearchParams(params);
  } else {
    searchParams = new URLSearchParams();
  }
  
  Object.entries(additionalParams).forEach(([key, value]) => {
    searchParams.set(key, value);
  });
  
  return searchParams.toString();
}

Usage Patterns

DOM Event Handling

import is from '@sindresorhus/is';

function setupEventDelegation(container: unknown, selector: string, handler: Function) {
  if (!is.htmlElement(container)) {
    throw new Error('Container must be an HTML element');
  }
  
  container.addEventListener('click', (event) => {
    const target = event.target;
    
    if (is.htmlElement(target) && target.matches(selector)) {
      handler(event, target);
    }
  });
}

// Usage
setupEventDelegation(document.body, '.button', (event, button) => {
  console.log('Button clicked:', button.textContent);
});

File Upload Processing

import is from '@sindresorhus/is';

async function handleFileUpload(file: unknown): Promise<FormData> {
  if (!is.blob(file)) {
    throw new Error('File must be a Blob or File');
  }
  
  // Validate file size (10MB limit)
  if (file.size > 10 * 1024 * 1024) {
    throw new Error('File too large (max 10MB)');
  }
  
  // Validate file type
  if (!file.type.startsWith('image/')) {
    throw new Error('Only image files are allowed');
  }
  
  const formData = new FormData();
  formData.append('file', file);
  formData.append('timestamp', Date.now().toString());
  
  return formData;
}

// Drag and drop handling
function setupDropZone(element: unknown) {
  if (!is.htmlElement(element)) {
    throw new Error('Drop zone must be an HTML element');
  }
  
  element.addEventListener('drop', async (event) => {
    event.preventDefault();
    
    const files = event.dataTransfer?.files;
    if (files) {
      for (const file of Array.from(files)) {
        try {
          const formData = await handleFileUpload(file);
          console.log('File ready for upload:', formData);
        } catch (error) {
          console.error('File upload error:', error);
        }
      }
    }
  });
}

URL and Query Parameter Handling

import is from '@sindresorhus/is';

function parseUrl(input: unknown): {url: URL; params: Record<string, string>} {
  let url: URL;
  
  if (is.urlInstance(input)) {
    url = input;
  } else if (is.string(input)) {
    try {
      url = new URL(input);
    } catch {
      throw new Error('Invalid URL string');
    }
  } else {
    throw new Error('Input must be URL instance or string');
  }
  
  const params: Record<string, string> = {};
  for (const [key, value] of url.searchParams.entries()) {
    params[key] = value;
  }
  
  return { url, params };
}

function buildApiUrl(baseUrl: string, endpoint: string, params?: unknown): string {
  const url = new URL(endpoint, baseUrl);
  
  if (params) {
    let searchParams: URLSearchParams;
    
    if (is.urlSearchParams(params)) {
      searchParams = params;
    } else if (is.plainObject(params)) {
      searchParams = new URLSearchParams(params as Record<string, string>);
    } else {
      throw new Error('Params must be URLSearchParams or plain object');
    }
    
    url.search = searchParams.toString();
  }
  
  return url.toString();
}

Form Data Processing

import is from '@sindresorhus/is';

function extractFormData(form: unknown): Record<string, string | File> {
  if (!is.htmlElement(form) || form.tagName !== 'FORM') {
    throw new Error('Input must be a form element');
  }
  
  const formData = new FormData(form as HTMLFormElement);
  const result: Record<string, string | File> = {};
  
  for (const [key, value] of formData.entries()) {
    if (is.string(value)) {
      result[key] = value;
    } else if (is.blob(value)) {
      result[key] = value as File;
    }
  }
  
  return result;
}

function validateFormData(data: unknown): FormData {
  if (!is.formData(data)) {
    throw new Error('Input must be FormData');
  }
  
  // Validate required fields
  const requiredFields = ['name', 'email'];
  for (const field of requiredFields) {
    if (!data.has(field)) {
      throw new Error(`Missing required field: ${field}`);
    }
  }
  
  return data;
}

Notes

  • HTML element checking validates DOM elements but not other node types (text, comment, etc.)
  • Blob checking includes File objects since File extends Blob
  • FormData is useful for multipart form submissions and file uploads
  • URL instance checking validates URL objects, not URL strings (use isUrlString() for strings)
  • URLSearchParams provides easy query string manipulation
  • Web API checks are browser-specific and may not work in Node.js environments
  • All web API checks work with TypeScript type guards for compile-time type narrowing
  • Consider environment detection before using these checks in universal/isomorphic code

Install with Tessl CLI

npx tessl i tessl/npm-sindresorhus--is

docs

assertions.md

async.md

collections.md

index.md

numbers.md

objects.md

primitives.md

strings.md

typed-arrays.md

validation.md

web-apis.md

tile.json