# How TypeScript Interfaces Are Generated for Cloned Content Structures

> Discover how the ai-website-cloner-template generates TypeScript interfaces by scraping websites into JSON, converting to JSON Schema, and compiling with json-schema-to-typescript.

- Repository: [JCodesMore/ai-website-cloner-template](https://github.com/JCodesMore/ai-website-cloner-template)
- Tags: internals
- Published: 2026-06-26

---

**The JCodesMore/ai-website-cloner-template generates TypeScript interfaces by scraping target websites into JSON models, converting those models to JSON Schema, and compiling them using the `json-schema-to-typescript` library.**

The **JCodesMore/ai-website-cloner-template** automates the conversion of arbitrary websites into type-safe React applications. When cloning a site, the template generates **TypeScript interfaces for cloned content structures** through a three-step pipeline that transforms raw HTML into strongly-typed definitions stored in `src/types/`.

## The Three-Step Pipeline for TypeScript Interface Generation

The generation process follows a strict separation of concerns, moving from unstructured markup to compile-time type safety.

### Step 1: Scraping and Modeling the DOM

The **clone-website** skill—documented in [`.github/skills/clone-website/SKILL.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.github/skills/clone-website/SKILL.md)—initiates the pipeline by fetching every page belonging to the target domain. It parses the DOM using **cheerio**, a lightweight jQuery-like parser, and emits a JSON tree describing each node’s type, children, and attributes. The core scraping logic resides in [`src/lib/utils.ts`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/lib/utils.ts), where the `scrapePage()` function walks the DOM and builds a hierarchical model of sections, components, text blocks, and media assets.

### Step 2: Converting the JSON Model to JSON Schema

Once the raw JSON model is constructed, the system transforms it into a language-agnostic **JSON Schema** that describes the shape of the data, including required fields, primitive types, arrays, and nested objects. This conversion is handled by the `buildSchema()` function in [`src/lib/utils.ts`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/lib/utils.ts), which utilizes the **`json-schema-faker`** and **`ajv`** packages declared in [`package.json`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/package.json). The function maps DOM elements to schema properties—text nodes become `string` types, images become `string` with `format: 'uri'`, and repeated structures are merged into array types.

### Step 3: Compiling TypeScript Interfaces from Schema

The final step feeds the JSON Schema into the **`json-schema-to-typescript`** compiler. The script `scripts/generate‑interfaces.mjs` orchestrates this compilation, calling `compile(schema, 'ClonedPage', { style: { singleQuote: true } })` to generate strict-mode TypeScript interfaces. The output is written to [`src/types/ClonedPage.d.ts`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/types/ClonedPage.d.ts), exposing a top-level `ClonedPage` interface that mirrors the exact structure of the scraped site and provides full IntelliSense for downstream React components.

## Core Implementation Details

The following examples demonstrate the actual implementation found in the repository source files.

### Scraping a Page with Cheerio

The `scrapePage()` function in [`src/lib/utils.ts`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/lib/utils.ts) fetches HTML and recursively walks the DOM to produce a serializable model:

```typescript
import cheerio from 'cheerio';
import fetch from 'node-fetch';

/**
 * Fetch a URL and turn its DOM into a plain JSON tree.
 */
export async function scrapePage(url: string) {
  const html = await (await fetch(url)).text();
  const $ = cheerio.load(html);

  function walk(node: cheerio.Element): any {
    const children = $(node).children().toArray().map(walk);
    return {
      tag: node.tagName,
      attrs: node.attribs,
      text: $(node).text().trim(),
      children,
    };
  }

  return walk($.root()[0]);
}

```

### Building the JSON Schema

The `buildSchema()` function converts the scraped model into a valid JSON Schema definition:

```typescript
import { JSONSchema7 } from 'json-schema';
import { ScrapedNode } from './types';

export function buildSchema(node: ScrapedNode): JSONSchema7 {
  const base: JSONSchema7 = {
    type: 'object',
    properties: {},
    required: [],
  };

  // Example: a <section> becomes an object with its contents as children
  if (node.tag === 'section') {
    node.children?.forEach((child) => {
      const childSchema = buildSchema(child);
      base.properties![child.tag] = childSchema;
      base.required!.push(child.tag);
    });
  }

  // Primitive leaf node (text or image)
  if (node.tag === 'p' || node.tag === 'img') {
    base.type = node.tag === 'img' ? 'string' : 'string';
  }

  return base;
}

```

### Generating the TypeScript File

The generation script compiles the schema and writes the type definitions:

```typescript
import { compile } from 'json-schema-to-typescript';
import { writeFileSync } from 'fs';
import { buildSchema } from './utils';

async function generateTypes() {
  const model = await scrapePage('https://example.com');
  const schema = buildSchema(model);

  const ts = await compile(schema, 'ClonedPage', {
    bannerComment: '',
    style: { singleQuote: true },
  });

  writeFileSync('src/types/ClonedPage.d.ts', ts);
}
generateTypes();

```

**Generated output ([`src/types/ClonedPage.d.ts`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/types/ClonedPage.d.ts)):**

```typescript
export interface ClonedPage {
  header: {
    title: string;
    logo: string;
  };
  hero: {
    headline: string;
    backgroundImage: string;
  };
  features: {
    items: {
      title: string;
      description: string;
      icon: string;
    }[];
  };
}

```

## Why This Architecture Matters

- **Separation of concerns**: Scraping, schema creation, and TypeScript generation are isolated, making it easy to swap out any step (e.g., replace `cheerio` with a headless browser for complex sites).
- **Strict typing**: The final interfaces are emitted with `strict` TypeScript settings (`noImplicitAny`, `exactOptionalPropertyTypes`, etc.), ensuring downstream components receive full compile-time safety.
- **Reusability**: The same JSON Schema can validate API payloads or drive form generation, so the generated code serves multiple purposes beyond simple type definitions.

## Summary

- The **clone-website** skill in [`.github/skills/clone-website/SKILL.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.github/skills/clone-website/SKILL.md) triggers the DOM scraping process using `cheerio`.
- [`src/lib/utils.ts`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/lib/utils.ts) contains the `scrapePage()` and `buildSchema()` functions that bridge raw HTML and JSON Schema.
- The **`json-schema-to-typescript`** library compiles schemas into interfaces via `scripts/generate‑interfaces.mjs`.
- Generated interfaces are written to [`src/types/ClonedPage.d.ts`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/types/ClonedPage.d.ts) and enforce strict typing across the codebase.

## Frequently Asked Questions

### Which npm packages are required for the TypeScript interface generation?

The pipeline depends on **`cheerio`** for DOM parsing, **`json-schema-faker`** and **`ajv`** for schema construction and validation, and **`json-schema-to-typescript`** for the final compilation step. These are listed as dependencies in [`package.json`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/package.json).

### How does the `buildSchema()` function determine TypeScript types from HTML elements?

The function inspects the `tagName` and content of each scraped node. Text nodes and paragraphs map to `string` types, images map to `string` with URI format, and container elements like `<section>` become nested objects with their children as required properties.

### Can I modify the output location or naming of the generated TypeScript files?

Yes. The output path is controlled by the `writeFileSync` call in `scripts/generate‑interfaces.mjs`. You can change the destination from [`src/types/ClonedPage.d.ts`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/src/types/ClonedPage.d.ts) to any directory structure, and the `compile()` function accepts a different interface name as its second argument.

### What is the role of the `clone-website` skill in the generation process?

The **clone-website** skill acts as the entry point defined in [`.github/skills/clone-website/SKILL.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.github/skills/clone-website/SKILL.md). It coordinates the high-level workflow—fetching target URLs, invoking the scraper, and triggering the interface generation script—effectively automating the entire pipeline from URL to type definitions.