or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

coordinates.mdcss-utilities.mdevent-handling.mdexecution-context.mdfocus-management.mdhooks.mdindex.mdmath-operations.mdtype-guards.mdtypescript-utilities.md
tile.json

typescript-utilities.mddocs/

TypeScript Utilities

Generic type manipulation helpers for advanced TypeScript patterns, useful for building type-safe drag and drop interfaces and utility functions.

Types

Arguments

Extracts function argument types as a tuple. Useful for creating wrapper functions that need to preserve exact parameter types.

/**
 * Extracts function argument types as a tuple
 * @template T - Function type to extract arguments from
 */
type Arguments<T> = T extends (...args: infer U) => any ? U : never;

Usage Examples:

import { type Arguments } from "@dnd-kit/utilities";

// Extract arguments from existing function
function createDragHandler(
  element: HTMLElement,
  options: { threshold: number; axis?: "x" | "y" },
  callback: (event: MouseEvent) => void
) {
  // Implementation here
}

// Create a type for the arguments
type DragHandlerArgs = Arguments<typeof createDragHandler>;
// Result: [HTMLElement, { threshold: number; axis?: "x" | "y" }, (event: MouseEvent) => void]

// Use in wrapper function
function createEnhancedDragHandler(...args: DragHandlerArgs) {
  console.log("Creating enhanced drag handler with args:", args);
  return createDragHandler(...args);
}

// Generic wrapper factory
function createWrapper<T extends (...args: any[]) => any>(
  originalFn: T
): (...args: Arguments<T>) => ReturnType<T> {
  return (...args: Arguments<T>) => {
    console.log("Calling function with args:", args);
    return originalFn(...args);
  };
}

// Event handler argument extraction
type MouseEventHandler = (event: MouseEvent) => void;
type MouseEventArgs = Arguments<MouseEventHandler>;
// Result: [MouseEvent]

function createEventProxy<T extends (...args: any[]) => any>(
  handler: T
): (...args: Arguments<T>) => void {
  return (...args: Arguments<T>) => {
    // Perform validation, logging, etc.
    console.log("Event proxy called with:", args);
    handler(...args);
  };
}

DeepRequired

Makes all properties and nested properties required, removing all optional flags recursively through the type hierarchy.

/**
 * Makes all properties and nested properties required
 * @template T - Type to make deeply required
 */
type DeepRequired<T> = {
  [K in keyof T]-?: Required<T[K]>;
};

Usage Examples:

import { type DeepRequired } from "@dnd-kit/utilities";

// Original interface with optional properties
interface DragConfig {
  element?: HTMLElement;
  options?: {
    threshold?: number;
    axis?: "x" | "y";
    constraints?: {
      minX?: number;
      maxX?: number;
      minY?: number;
      maxY?: number;
    };
  };
  callbacks?: {
    onStart?: (event: MouseEvent) => void;
    onMove?: (event: MouseEvent) => void;
    onEnd?: (event: MouseEvent) => void;
  };
}

// Make all properties required
type RequiredDragConfig = DeepRequired<DragConfig>;
/* Result:
{
  element: HTMLElement;
  options: {
    threshold: number;
    axis: "x" | "y";
    constraints: {
      minX: number;
      maxX: number;
      minY: number;
      maxY: number;
    };
  };
  callbacks: {
    onStart: (event: MouseEvent) => void;
    onMove: (event: MouseEvent) => void;
    onEnd: (event: MouseEvent) => void;
  };
}
*/

// Function that requires complete configuration
function initializeDragSystem(config: RequiredDragConfig) {
  // All properties are guaranteed to exist
  config.element.addEventListener("mousedown", config.callbacks.onStart);
  
  // No need for optional chaining
  const threshold = config.options.threshold;
  const constraints = config.options.constraints;
  
  console.log("Drag system initialized with complete config");
}

// Default configuration provider
function createDefaultDragConfig(): RequiredDragConfig {
  return {
    element: document.createElement("div"),
    options: {
      threshold: 5,
      axis: "x",
      constraints: {
        minX: 0,
        maxX: window.innerWidth,
        minY: 0,
        maxY: window.innerHeight
      }
    },
    callbacks: {
      onStart: () => console.log("Drag started"),
      onMove: () => console.log("Drag moved"),
      onEnd: () => console.log("Drag ended")
    }
  };
}

// Merge partial config with defaults
function mergeDragConfig(
  partial: DragConfig,
  defaults: RequiredDragConfig
): RequiredDragConfig {
  return {
    element: partial.element ?? defaults.element,
    options: {
      threshold: partial.options?.threshold ?? defaults.options.threshold,
      axis: partial.options?.axis ?? defaults.options.axis,
      constraints: {
        minX: partial.options?.constraints?.minX ?? defaults.options.constraints.minX,
        maxX: partial.options?.constraints?.maxX ?? defaults.options.constraints.maxX,
        minY: partial.options?.constraints?.minY ?? defaults.options.constraints.minY,
        maxY: partial.options?.constraints?.maxY ?? defaults.options.constraints.maxY
      }
    },
    callbacks: {
      onStart: partial.callbacks?.onStart ?? defaults.callbacks.onStart,
      onMove: partial.callbacks?.onMove ?? defaults.callbacks.onMove,
      onEnd: partial.callbacks?.onEnd ?? defaults.callbacks.onEnd
    }
  };
}

FirstArgument

Extracts the type of the first argument from a function. Useful for creating utilities that work with the primary parameter of callback functions.

/**
 * Extracts the type of the first argument from a function
 * @template T - Function type to extract first argument from
 */
type FirstArgument<T> = T extends (firstArg: infer U, ...args: Array<any>) => any
  ? U
  : never;

Usage Examples:

import { type FirstArgument } from "@dnd-kit/utilities";

// Extract first argument type from event handlers
type MouseEventHandler = (event: MouseEvent, extra: string) => void;
type MouseEventType = FirstArgument<MouseEventHandler>;
// Result: MouseEvent

type DragHandler = (data: { x: number; y: number }, element: HTMLElement) => void;
type DragData = FirstArgument<DragHandler>;
// Result: { x: number; y: number }

// Create type-safe event proxy
function createEventProxy<T extends (event: any, ...args: any[]) => any>(
  handler: T
): (event: FirstArgument<T>) => void {
  return (event: FirstArgument<T>) => {
    // Validate or transform the event
    console.log("Proxying event:", event);
    handler(event, "additional", "arguments");
  };
}

// React component prop extraction
interface ButtonProps {
  onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
  onDoubleClick: (event: React.MouseEvent<HTMLButtonElement>, target: HTMLElement) => void;
}

type ClickEvent = FirstArgument<ButtonProps['onClick']>;
// Result: React.MouseEvent<HTMLButtonElement>

type DoubleClickEvent = FirstArgument<ButtonProps['onDoubleClick']>;
// Result: React.MouseEvent<HTMLButtonElement>

// Generic callback wrapper
function createCallbackWrapper<T extends (first: any, ...rest: any[]) => any>(
  callback: T,
  middleware: (data: FirstArgument<T>) => FirstArgument<T>
): T {
  return ((...args: any[]) => {
    const [first, ...rest] = args;
    const processedFirst = middleware(first);
    return callback(processedFirst, ...rest);
  }) as T;
}

// Usage with drag handlers
const originalDragHandler = (data: { x: number, y: number }, element: HTMLElement) => {
  console.log("Dragging to:", data);
};

const wrappedDragHandler = createCallbackWrapper(
  originalDragHandler,
  (data) => ({
    x: Math.round(data.x),
    y: Math.round(data.y)
  })
);

// Event handler factory
function createEventHandler<T extends (event: any, ...args: any[]) => any>(
  handler: T,
  validator: (event: FirstArgument<T>) => boolean
): T {
  return ((...args: any[]) => {
    const [event, ...rest] = args;
    if (validator(event)) {
      return handler(event, ...rest);
    }
    console.warn("Event validation failed");
  }) as T;
}

// Create validated mouse handler
const validatedMouseHandler = createEventHandler(
  (event: MouseEvent) => console.log("Valid mouse event"),
  (event) => event instanceof MouseEvent && event.button === 0
);

Without

Creates a type by excluding specified keys from another type. Useful for creating modified versions of interfaces or for implementing omit-like functionality.

/**
 * Creates a type by excluding specified keys from T
 * @template T - Source type
 * @template K - Keys to exclude from T
 */
type Without<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

Usage Examples:

import { type Without } from "@dnd-kit/utilities";

// Original interface
interface FullDragConfig {
  element: HTMLElement;
  threshold: number;
  axis: "x" | "y" | "both";
  onStart: (event: MouseEvent) => void;
  onMove: (event: MouseEvent) => void;
  onEnd: (event: MouseEvent) => void;
  disabled: boolean;
}

// Create type without event handlers
type DragConfigWithoutEvents = Without<FullDragConfig, 'onStart' | 'onMove' | 'onEnd'>;
/* Result:
{
  element: HTMLElement;
  threshold: number;
  axis: "x" | "y" | "both";
  disabled: boolean;
}
*/

// Create type without element (for configuration only)
type DragOptions = Without<FullDragConfig, 'element'>;
/* Result:
{
  threshold: number;
  axis: "x" | "y" | "both";
  onStart: (event: MouseEvent) => void;
  onMove: (event: MouseEvent) => void;
  onEnd: (event: MouseEvent) => void;
  disabled: boolean;
}
*/

// Function that accepts partial configuration
function createDragElement(
  element: HTMLElement,
  config: Without<FullDragConfig, 'element'>
) {
  const fullConfig: FullDragConfig = {
    element,
    ...config
  };
  
  return initializeDrag(fullConfig);
}

// Create immutable update functions
function updateDragConfig<K extends keyof FullDragConfig>(
  config: FullDragConfig,
  key: K,
  value: FullDragConfig[K]
): FullDragConfig {
  return { ...config, [key]: value };
}

// Create configuration builder
class DragConfigBuilder {
  private config: Partial<FullDragConfig> = {};
  
  element(el: HTMLElement): DragConfigBuilder {
    this.config.element = el;
    return this;
  }
  
  threshold(val: number): DragConfigBuilder {
    this.config.threshold = val;
    return this;
  }
  
  // Method that returns config without builder methods
  build(): Without<FullDragConfig, never> {
    return this.config as FullDragConfig;
  }
  
  // Get partial config for validation
  getPartial(): Without<FullDragConfig, 'element'> | Partial<FullDragConfig> {
    return this.config;
  }
}

// React props manipulation
interface ComponentProps {
  className?: string;
  style?: React.CSSProperties;
  onClick?: (event: React.MouseEvent) => void;
  onDrag?: (event: React.DragEvent) => void;
  children: React.ReactNode;
  disabled?: boolean;
}

// Create props without event handlers for styling-only component
type StyleOnlyProps = Without<ComponentProps, 'onClick' | 'onDrag'>;

function StyleOnlyComponent(props: StyleOnlyProps) {
  return <div className={props.className} style={props.style}>{props.children}</div>;
}

// Create props without children for wrapper component
type WrapperProps = Without<ComponentProps, 'children'>;

function WrapperComponent(props: WrapperProps) {
  return (
    <div {...props}>
      <div>Wrapper content</div>
    </div>
  );
}

// API response type manipulation
interface APIResponse {
  data: any;
  status: number;
  headers: Record<string, string>;
  timestamp: string;
  requestId: string;
}

// Client-side type without server metadata
type ClientResponse = Without<APIResponse, 'headers' | 'requestId'>;

function processClientResponse(response: ClientResponse) {
  // Only access client-relevant properties
  console.log("Status:", response.status);
  console.log("Data:", response.data);
  console.log("Time:", response.timestamp);
}