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 token reference as typed data:grFoundationTokens,grThemeTokens,grComponentTokens,grDerivedTokensand the types for them. The source is the sametokens/*.jsonthe 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
| 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.