Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

sveld

carbon-design-system10.4kApache-2.00.22.1TypeScript support: included

Generate TypeScript definitions for your Svelte components.

svelte, svelte component, documentation, docgen, typescript, definitions, JSDocs

readme

sveld

NPM GitHub npm downloads to date

sveld is a TypeScript definition generator for Svelte components. It analyzes props, events, slots, and other component features through static analysis. Types and signatures can be defined using JSDoc notation. The tool can also generate component documentation in Markdown and JSON formats.

The purpose of this project is to make third party Svelte component libraries compatible with the Svelte Language Server and TypeScript with minimal effort required by the author. For example, TypeScript definitions may be used during development via intelligent code completion in Integrated Development Environments (IDE) like VSCode.

Carbon Components Svelte uses this library to auto-generate component types and API metadata:

Please note that the generated TypeScript definitions require Svelte version 3.55 or greater.


Given a Svelte component, sveld can infer basic prop types to generate TypeScript definitions compatible with the Svelte Language Server:

Button.svelte

<script>
  export let type = "button";
  export let primary = false;
</script>

<button {...$$restProps} {type} class:primary on:click>
  <slot>Click me</slot>
</button>

The generated definition extends the official SvelteComponentTyped interface exported from Svelte.

Button.svelte.d.ts

import type { SvelteComponentTyped } from "svelte";
import type { SvelteHTMLElements } from "svelte/elements";

type $RestProps = SvelteHTMLElements["button"];

type $Props = {
  /**
   * @default "button"
   */
  type?: string;

  /**
   * @default false
   */
  primary?: boolean;

  [key: `data-${string}`]: any;
};

export type ButtonProps = Omit<$RestProps, keyof $Props> & $Props;

export default class Button extends SvelteComponentTyped<
  ButtonProps,
  { click: WindowEventMap["click"] },
  { default: {} }
> {}

Sometimes, inferring prop types is insufficient.

Prop/event/slot types and signatures can be augmented using JSDoc notations.

/** @type {"button" | "submit" | "reset"} */
export let type = "button";

/**
 * Set to `true` to use the primary variant
 */
export let primary = false;

The accompanying JSDoc annotations would generate the following:

import type { SvelteHTMLElements } from "svelte/elements";

type $RestProps = SvelteHTMLElements["button"];

type $Props = {
  /**
   * @default "button"
   */
  type?: "button" | "submit" | "reset";

  /**
   * Set to `true` to use the primary variant
   * @default false
   */
  primary?: boolean;
};

export type ButtonProps = Omit<$RestProps, keyof $Props> & $Props;

export default class Button extends SvelteComponentTyped<
  ButtonProps,
  { click: WindowEventMap["click"] },
  { default: {} }
> {}

Table of Contents

Approach

sveld uses the Svelte compiler to statically analyze Svelte components exported from a library to generate documentation useful to the end user.

Extracted metadata include:

  • props
  • slots
  • forwarded events
  • dispatched events
  • $$restProps

This library adopts a progressively enhanced approach. Any property type that cannot be inferred (e.g., "hello" is a string) falls back to "any" to minimize incorrectly typed properties or signatures. To mitigate this, the library author can add JSDoc annotations to specify types that cannot be reliably inferred. This represents a progressively enhanced approach because JSDocs are comments that can be ignored by the compiler.

Usage

Installation

Install sveld as a development dependency.

# npm
npm i -D sveld

# pnpm
pnpm i -D sveld

# Bun
bun i -D sveld

# Yarn
yarn add -D sveld

Rollup

Import and add sveld as a plugin to your rollup.config.js.

// rollup.config.js
import svelte from "rollup-plugin-svelte";
import resolve from "@rollup/plugin-node-resolve";
import sveld from "sveld";

export default {
  input: "src/index.js",
  output: {
    format: "es",
    file: "lib/index.mjs",
  },
  plugins: [svelte(), resolve(), sveld()],
};

When building the library, TypeScript definitions are emitted to the types folder by default.

Customize the output folder using the typesOptions.outDir option.

The following example emits the output to the dist folder:

sveld({
+  typesOptions: {
+    outDir: 'dist'
+  }
})

The tests/e2e folder contains example set-ups:

CLI

The CLI uses the "svelte" field from your package.json as the entry point:

npx sveld

Generate documentation in JSON and/or Markdown formats using the following flags:

npx sveld --json --markdown

Node.js

You can also use sveld programmatically in Node.js.

If no input is specified, sveld will infer the entry point based on the package.json#svelte field.

const { sveld } = require("sveld");
const pkg = require("./package.json");

sveld({
  input: "./src/index.js",
  glob: true,
  markdown: true,
  markdownOptions: {
    onAppend: (type, document, components) => {
      if (type === "h1")
        document.append("quote", `${components.size} components exported from ${pkg.name}@${pkg.version}.`);
    },
  },
  json: true,
  jsonOptions: {
    outFile: "docs/src/COMPONENT_API.json",
  },
});

jsonOptions.outDir

If json is true, a COMPONENT_API.json file will be generated at the root of your project. This file contains documentation for all components.

Use the jsonOptions.outDir option to specify the folder for individual JSON files to be emitted.

sveld({
  json: true,
  jsonOptions: {
    // an individual JSON file will be generated for each component API
    // e.g. "docs/Button.api.json"
    outDir: "docs",
  },
});

Publishing to NPM

TypeScript definitions are outputted to the types folder by default. Don't forget to include the folder in your package.json when publishing the package to NPM.

{
  "svelte": "./src/index.js",
  "main": "./lib/index.mjs",
+ "types": "./types/index.d.ts",
  "files": [
    "src",
    "lib",
+   "types",
  ]
}

Available Options

By default, only TypeScript definitions are generated.

To generate documentation in Markdown and JSON formats, set markdown and json to true.

sveld({
+  markdown: true,
+  json: true,
})

API Reference

@type

Without a @type annotation, sveld will infer the primitive type for a prop:

export let kind = "primary";
// inferred type: "string"

Use the @type tag to explicitly document the type. In the following example, the kind property has an enumerated (enum) type.

Signature:

/**
 * Optional description
 * @type {Type}
 */

Example:

/**
 * Specify the kind of button
 * @type {"primary" | "secondary" | "tertiary"}
 */
export let kind = "primary";

/**
 * Specify the Carbon icon to render
 * @type {typeof import("carbon-icons-svelte").CarbonIcon}
 */
export let renderIcon = Close20;

@typedef

The @typedef tag can be used to define a common type that is used multiple times within a component. All typedefs defined in a component will be exported from the generated TypeScript definition file.

Signature:

/**
 * @typedef {Type} TypeName
 */

Example:

/**
 * @typedef {string} AuthorName
 * @typedef {{ name?: AuthorName; dob?: string; }} Author
 */

/** @type {Author} */
export let author = {};

/** @type {Author[]} */
export let authors = [];

@slot

Use the @slot tag for typing component slots. Note that @slot is a non-standard JSDoc tag.

Descriptions are optional for named slots. Currently, the default slot cannot have a description.

Signature:

/**
 * @slot {Type} slot-name [slot description]
 */

Omit the `slot-name` to type the default slot.

/**
 * @slot {Type}
 */

Example:

<script>
  /**
   * @slot {{ prop: number; doubled: number; }}
   * @slot {{}} title
   * @slot {{ prop: number }} body - Customize the paragraph text.
   */

  export let prop = 0;
</script>

<h1>
  <slot {prop} doubled={prop * 2} />
  <slot name="title" />
</h1>

<p>
  <slot name="body" {prop} />
</p>

@event

Use the @event tag to type dispatched events. An event name is required and a description optional.

Use null as the value if no event detail is provided.

Signature:

/**
 * @event {EventDetail} eventname [event description]
 */

Example:

/**
 * @event {{ key: string }} button:key
 * @event {null} key – Fired when `key` changes.
 */

export let key = "";

import { createEventDispatcher } from "svelte";

const dispatch = createEventDispatcher();

$: dispatch("button:key", { key });
$: if (key) dispatch("key");

Output:

export default class Component extends SvelteComponentTyped<
  ComponentProps,
  {
    "button:key": CustomEvent<{ key: string }>;
    /** Fired when `key` changes. */ key: CustomEvent<null>;
  },
  {}
> {}

@restProps

sveld can pick up inline HTML elements that $$restProps is forwarded to. However, it cannot infer the underlying element for instantiated components.

You can use the @restProps tag to specify the element tags that $$restProps is forwarded to.

Signature:

/**
 * Single element
 * @restProps {tagname}
 *
 * Multiple elements
 * @restProps {tagname-1 | tagname-2 | tagname-3}
 */

Example:

<script>
  /** @restProps {h1 | button} */
  export let edit = false;

  import Button from "../";
</script>

{#if edit}
  <Button {...$$restProps} />
{:else}
  <h1 {...$$restProps}><slot /></h1>
{/if}

@extends

In some cases, a component may be based on another component. The @extends tag can be used to extend generated component props.

Signature:

/**
 * @extends {<relative path to component>} ComponentProps
 */

Example:

/** @extends {"./Button.svelte"} ButtonProps */

export const secondary = true;

import Button from "./Button.svelte";

@generics

Currently, to define generics for a Svelte component, you must use generics attribute on the script tag. Note that this feature is experimental and may change in the future.

However, the generics attribute only works if using lang="ts"; the language server will produce an error if generics is used without specifying lang="ts".

<!-- This causes an error because `lang="ts"` must be used. -->
<script generics="Row extends DataTableRow = any"></script>

Because sveld is designed to support JavaScript-only usage as a baseline, the API design to specify generics uses a custom JSDoc tag @generics.

Signature:

/**
 * @generics {GenericParameter} GenericName
 */

Example

/**
 * @generics {Row extends DataTableRow = any} Row
 */

The generated TypeScript definition will resemble the following:

export default class Component<Row extends DataTableRow = any> extends SvelteComponentTyped<
  ComponentProps<Row>,
  Record<string, any>,
  Record<string, any>
> {}

For a parameter list, the name should be comma-separated but not include spaces.

/**
 * @generics {Param1, Param2} Name1,Name2
 */
export default class Component<Param1, Param2> extends SvelteComponentTyped<
  ComponentProps<Name1, Name2>,
  Record<string, any>,
  Record<string, any>
> {}

@component comments

The Svelte Language Server supports component-level comments through the following syntax: <!-- @component [comment] -->.

sveld will copy these over to the exported default component in the TypeScript definition.

Example:

<!-- @component
@example
<Button>
  Text
</Button>
-->
<button>
  <slot />
</button>

Output:

/**
 * @example
 * <Button>
 *   Text
 * </Button>
 */
export default class Button extends SvelteComponentTyped<ButtonProps, {}, { default: {} }> {}

Contributing

Refer to the contributing guidelines.

License

Apache-2.0

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

0.22.1 - 2025-02-17

Fixes

  • improve error handling for missing Svelte entry file

0.22.0 - 2024-11-10

Breaking Changes

  • upgrade prettier to v3 (by default, trailingComma is now "all")

0.21.0 - 2024-10-27

Breaking Changes

  • use type alias instead of interface for exported component props type

Fixes

  • prefix internal RestProps type with $ to avoid conflicts with Rest.svelte as a component name

0.20.3 - 2024-10-25

Fixes

  • use WindowEventMap for cut/copy/paste events

0.20.2 - 2024-09-13

Fixes

  • reduce dependencies by upgrading svelte-preprocess from v5 to v6

0.20.1 - 2024-09-12

Fixes

  • reduce dependencies by replacing fast-glob with tinyglobby

0.20.0 - 2024-04-20

Features

  • support component generics via the custom @generics tag

0.19.2 - 2024-04-08

Fixes

  • ComponentParser should remove carriage returns (Windows)

0.19.1 - 2023-10-17

Fixes

  • only print outFile when writing Markdown file
  • upgrade svelte-preprocess and typescript to ameliorate peer dependency warning

0.19.0 - 2023-07-19

Breaking Changes

  • if using Svelte 3, the generated TypeScript definitions now require version 3.55 or higher

Features

  • support Svelte 4 in the generated TypeScript definitions

0.18.1 - 2023-06-04

  • allow data-* attributes for props forwarded to HTML elements for `svelte-check@3.x` compatibility

0.18.0 - 2022-10-22

  • support @slot tag descriptions for named slots
  • support @event tag descriptions
  • remove sveltekit:* attributes from type definitions

0.17.2 - 2022-06-13

  • handle export {} in script block

0.17.1 - 2022-06-02

  • use correct type for forwarded cut/copy/paste events

0.17.0 - 2022-05-21

  • remove @required tag; directly infer if a prop is required

0.16.1 - 2022-05-20

  • additional_tags can be undefined

0.16.0 - 2022-05-19

  • support @required tag to denote required component props
  • support wildcard export in svelte entry point

0.15.3 - 2022-05-14

  • preserve JSDoc tags in prop comments

0.15.2 - 2022-05-13

  • dispatched event type without detail should default to null, not any

0.15.1 - 2022-05-01

  • function exported from <script context="module"> should be typed as functions, not types

0.15.0 - 2022-04-14

  • add jsonOptions.outDir option to emit JSON files for individual components
  • add sveltekit:reload attributes to props that extend a attributes

0.14.1 - 2022-04-09

  • svg $$restProps should extend the correct attributes

0.14.0 - 2022-04-09

  • add sveltekit:prefetch, sveltekit:noscroll attributes to props that extend a attributes
  • use type-only imports for SvelteComponentTyped and extended props

0.13.4 - 2022-02-26

  • use file name as module name if library only has a single default export

0.13.3 - 2022-02-13

  • component module exports should not be recognized as accessors

0.13.2 - 2022-02-10

  • do not wrap TS @event detail in CustomEvent if type contains CustomEvent

0.13.1 - 2022-01-22

  • return original entry point instead of resolved path in getSvelteEntry

0.13.0 - 2022-01-22

  • export sveld for programmatic usage
  • upgrade prettier, rollup, svelte, svelte-preprocess, typescript

0.12.1 - 2022-01-20

  • specify @default undefined for undefined prop values (i.e., let prop1; let prop2 = undefined)

0.12.0 - 2022-01-02

  • support props defined via renamed exports (i.e., let className; export { className as class })

0.11.1 - 2021-12-31

  • replace backslashes with forward slashes in COMPONENT_API.json filePath values

0.11.0 - 2021-12-16

  • support writing <!-- @component --> comments in Svelte components to TypeScript definitions

0.10.2 - 2021-08-29

  • tolerate slot spread syntax (<slot {...props} />) when parsing Svelte components

0.10.1 - 2021-08-28

  • include .svelte extension in index.d.ts exports

0.10.0 - 2021-08-28

  • use .svelte.d.ts for Svelte files in type definitions to enable direct imports

0.9.0 - 2021-08-28

  • omit @constant, @default notations for component accessors

0.8.3 - 2021-07-29

  • replace backslashes with slashes on Windows when reading Svelte files using the glob method

0.8.2 - 2021-07-11

  • write constant props as accessors in the SvelteComponentTyped interface

0.8.1 - 2021-07-10

  • type function declarations as accessors in the SvelteComponentTyped interface
  • omit module name from generated TypeScript class if it's the reserved keyword "default"
  • move typescript to direct dependencies

0.8.0 - 2021-06-17

  • use svelte-preprocess to preprocess TypeScript in Svelte files and remove style blocks

0.7.1 - 2021-02-20

  • only parse files with the .svelte file extension

0.7.0 - 2021-02-06

  • add a glob option to resolve Svelte files from entry file exports using fast-glob (default is false)

0.6.1 - 2021-01-09

  • use parsed exports to determine module name, Svelte source file path

0.6.0 - 2021-01-09

  • use acorn to parse/create TypeScript exports
  • use fast-glob to collect all *.svelte files from the Svelte source folder specified in package.json#svelte
  • format TS definitions using a prettier printWidth of 80 instead of 120

Breaking Changes

  • filePath in generated JSON output is relative instead of absolute (normalized using path.normalize)

0.5.0 - 2020-12-05

  • generate TypeScript definitions to use SvelteComponentTyped interface instead of SvelteComponent

Breaking Changes

  • Svelte version >=3.31 is required to use generated TypeScript definitions

0.4.2 - 2020-11-25

Fixes

  • account for : when clamping object keys

0.4.1 - 2020-11-25

Fixes

  • clamp slot/event keys in TypeScript definitions

0.4.1 - 2020-11-25

  • output format for TypeScript definitions extends SvelteComponent instead of stubbing class internals used by the Svelte Language Server

Breaking Changes

  • Svelte version >=3.30 is required to use generated TypeScript definitions

0.3.0 - 2020-11-25

  • export component typedefs in TypeScript definitions

0.2.1 - 2020-11-19

  • extend interface for empty props use case

0.2.0 - 2020-11-19

  • support @extends tag to extend imported component prop interfaces

0.1.0 - 2020-11-19

  • support @restProps tag
  • fix "undefined" event by checking if the event name is undefined

0.1.0-rc.5 - 2020-11-18

  • use package.json#svelte for the entry point to uncompiled Svelte source code

0.1.0-rc.4 - 2020-11-17

  • add rollup to dependencies

0.1.0-rc.3 - 2020-11-17

  • add svelte to dependencies

0.1.0-rc.2 - 2020-11-17

  • add cli.js to publishable files

0.1.0-rc.1 - 2020-11-17

  • enable CLI usage by wrapping Rollup plugin

0.1.0-rc.0 - 2020-11-16

  • initial release