# TypeScript

> Types arrive with the subpath: props, emits, the instance and the tokens. Plus web-types for JetBrains, which almost nobody knows about.

- Page: https://granularity.tech/docs/typescript
- Last reviewed: 2026-10-15

The package is written in TypeScript, and the types are not collected into one
shared `.d.ts`: every subpath has its own. Import a component and you get its
types without pulling in the declarations of all the others.

## What a component subpath exports

```ts
import {
  GrButton,
  type GrButtonProps,
  type GrButtonInstance,
  type GrButtonTone,
} from '@feugene/granularity/components/GrButton'
```

Three types are exported next to a component — `GrXProps`, `GrXEmits` and
`GrXInstance`, the last one on components that expose something through
`defineExpose`. The set is held by a gate in the package. The other names —
`GrXConfigurableProps`, `grXConfig`, `grXSafelist` — are not on every component.
The naming scheme is still the same for every component, which is more useful
than a list:

| Type | What it describes |
|---|---|
| `GrXProps` | The component's props |
| `GrXEmits` | Events — where there are any |
| `GrXInstance` | The public instance — on components that expose something |
| `GrXSize`, `GrXTone`, `GrXVariant` | The allowed values of the matching prop |
| `GrXConfigurableProps` | The subset of props configurable through `GrConfigProvider` |
| `grXConfig`, `grXSafelist` | Values rather than types: the component's config and its safelist for the pipeline |

`GrXInstance` comes in handy wherever the component is addressed by reference:

```vue
<script setup lang="ts">
import { useTemplateRef } from 'vue'
import type { GrDataTableInstance } from '@feugene/granularity/components/GrDataTable'

const table = useTemplateRef<GrDataTableInstance>('table')
</script>
```

Composite components also hand out the types of their data — for the table that
is `GrDataColumn`, `GrDataTableRowKey`, `GrDataTableSortDir` and everything else
you would otherwise have to declare in your own code and keep in sync by hand.

## Types unrelated to components

- `@feugene/granularity/tokens` — the token reference as **typed data**:
  `grFoundationTokens`, `grThemeTokens`, `grComponentTokens`, `grDerivedTokens`
  and the types for them. The source is the same `tokens/*.json` the CSS is
  generated from, so they cannot drift from the real values.
- `@feugene/granularity/directives` — the directives together with the types of
  their arguments.
- `@feugene/granularity/fileValidation` — file validation rules as a separate
  module: there the types are the main value rather than a side effect.

:::callout{type="info"}
The token reference is deliberately **not** re-exported from the package root.
It is data for documentation and tooling; an application does not need it at
runtime, and dragging it into the main bundle would break the very promise all of
this exists for.
:::

## JetBrains: completion out of the box

The package builds and publishes `web-types.json` — a format the JetBrains IDEs
read by themselves. Nothing needs configuring: after installation WebStorm,
PhpStorm and IDEA know the package's components in templates, their props with
defaults and descriptions, and their slots. Events and directives are not in
the file.

:::callout{type="info"}
The file is declared in `package.json` through the `web-types` field and sits in
`dist`.
:::

## VS Code and the rest

| Environment | What works |
|---|---|
| VS Code + Vue (Official) | Types from `.d.ts` and descriptions from JSDoc |
| Zed, Neovim | The same through Vue LSP; nothing to configure on the package's side |
| JetBrains | Plus `web-types.json` |

## Project setup

The package requires nothing specific, but two points save an evening:

:::steps
1. **`"moduleResolution": "bundler"`** (or `"node16"`) in `tsconfig.json`. With `"node"` TypeScript does not read the `exports` field and will not find the subpath types — a component import is flagged as an error even though it builds.
2. **`vue-tsc` instead of `tsc`** for checking templates. The package types its slots and events, and without `vue-tsc` that part is not checked at all.
:::

If the types are "not found" specifically on a subpath while the root imports
fine, it is almost always the first point; the case with the compiler's own
message is worked through on the
[troubleshooting](/docs/troubleshooting) page.
