TypeScript
Types arrive with the subpath: props, emits, the instance and the tokens. Plus web-types for JetBrains, which almost nobody knows about.
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
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:
<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 per-component token registrygrComponentTokensas typed data, with its types. The source is the same componenttokens.jsonfiles the CSS is generated from, so it cannot drift from the real values.@feugene/granularity-tokens— the global tokens the same way:grFoundationTokens,grRoleTokens,grDerivedTokens, thegrThemeCatalogtheme catalogue and theGrThemeDatatype of theme data. The values live in the theme data and are loaded on demand.virtual:granum/themes— the build’s mode manifest. The types of granum’s virtual modules come with a single/// <reference types="@feugene/granum/client" />line in any.d.ts; the mode and theme names for your own switch are theGrModeNameandGrThemeIdtypes from the core root.@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
| 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:
"moduleResolution": "bundler"(or"node16") intsconfig.json. With"node"TypeScript does not read theexportsfield and will not find the subpath types — a component import is flagged as an error even though it builds.vue-tscinstead oftscfor checking templates. The package types its slots and events, and withoutvue-tscthat 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.