TypeScript

  • Integrations
  • 3 min
  • 2 snippets

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

Reviewed 2026-10-15

On this page

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:

TypeWhat it describes
GrXPropsThe component’s props
GrXEmitsEvents — where there are any
GrXInstanceThe public instance — on components that expose something
GrXSize, GrXTone, GrXVariantThe allowed values of the matching prop
GrXConfigurablePropsThe subset of props configurable through GrConfigProvider
grXConfig, grXSafelistValues 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.

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.

The file is declared in package.json through the web-types field and sits in dist.

VS Code and the rest

EnvironmentWhat works
VS Code + Vue (Official)Types from .d.ts and descriptions from JSDoc
Zed, NeovimThe same through Vue LSP; nothing to configure on the package’s side
JetBrainsPlus web-types.json

Project setup

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

  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 page.