mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
6.4 KiB
6.4 KiB
TypeScript JSON Abstraction Pattern
Concept Overview
Just as we've abstracted CSS into declarative JSON schemas (styles.json), this demonstrates how TypeScript type definitions can be represented in a similar JSON format.
Pattern Comparison
CSS Pattern (styles.json V2)
Declarative JSON → StylesCompiler → CSS Output
TypeScript Pattern (types.json)
Declarative JSON → TypeScriptCompiler → .d.ts Output
Architecture
1. Schema Structure
File Location: packages/{package}/seed/types.json
Core Sections:
- tokens: Reusable primitive type aliases
- interfaces: Object type definitions
- types: Union types, literal types
- generics: Generic type definitions
- rules: Type constraints and modifiers
- exports: Export configuration
- environments: Target environments (ESM, CJS, TypeScript)
- composition: Type intersections and combinations
2. Benefits of This Approach
- Non-Developer Friendly: JSON is easier to read/edit than TypeScript syntax
- Composable: Build complex types from simple building blocks
- Multi-Target: Single source generates multiple output formats
- Versionable: Schema versioning allows evolution
- Debuggable: Can build visualization tools (like StylesPanel)
- Consistent: Mirrors the proven styles.json pattern
3. Example: From JSON to TypeScript
Input (types.json):
{
"interfaces": [
{
"name": "ButtonProps",
"extends": ["BaseComponentProps"],
"properties": {
"variant": {
"type": "'primary' | 'secondary'",
"optional": false
},
"size": {
"type": "'small' | 'medium' | 'large'",
"default": "'medium'"
}
}
}
]
}
Output (compiled TypeScript):
export interface ButtonProps extends BaseComponentProps {
variant: 'primary' | 'secondary';
size?: 'small' | 'medium' | 'large';
}
4. Compiler Implementation Sketch
class TypeScriptCompiler {
private schema: TypeScriptSchema;
compile(): string {
const output: string[] = [];
// Compile tokens
if (this.schema.tokens) {
output.push(this.compileTokens(this.schema.tokens));
}
// Compile interfaces
if (this.schema.interfaces) {
output.push(...this.schema.interfaces.map(i => this.compileInterface(i)));
}
// Compile types
if (this.schema.types) {
output.push(...this.schema.types.map(t => this.compileType(t)));
}
// Apply rules/modifiers
return this.applyRules(output.join('\n\n'));
}
private compileInterface(def: InterfaceDefinition): string {
const ext = def.extends?.length ? ` extends ${def.extends.join(', ')}` : '';
const props = Object.entries(def.properties)
.map(([key, prop]) => {
const optional = prop.optional ? '?' : '';
const readonly = prop.readonly ? 'readonly ' : '';
return ` ${readonly}${key}${optional}: ${prop.type};`;
})
.join('\n');
return `export interface ${def.name}${ext} {\n${props}\n}`;
}
private compileType(def: TypeDefinition): string {
if (def.kind === 'union') {
return `export type ${def.name} = ${def.values.join(' | ')};`;
}
return `export type ${def.name} = ${def.definition};`;
}
}
5. Integration Points
Following the styles.json pattern:
// Similar to loadPackageStyles()
async function loadPackageTypes(packageId: string): Promise<string> {
const response = await fetch(`/packages/${packageId}/seed/types.json`);
const schema = await response.json();
const compiler = new TypeScriptCompiler(schema);
return compiler.compile();
}
// Generate .d.ts files at build time
function generateTypeDefinitions() {
const packages = getPackageList();
for (const pkg of packages) {
const typeSchema = loadTypeSchema(pkg);
const compiler = new TypeScriptCompiler(typeSchema);
const output = compiler.compile();
fs.writeFileSync(
`packages/${pkg}/dist/types.d.ts`,
output
);
}
}
6. Advanced Features
Composition (like styles.json appearance layers):
{
"composition": [
{
"name": "EnhancedButtonProps",
"kind": "intersection",
"types": [
"ButtonProps",
"AccessibilityProps",
"AnalyticsProps"
]
}
]
}
Rules (like styles.json selector rules):
{
"rules": [
{
"selector": {
"interfaceName": "UserData",
"property": "id"
},
"modifiers": ["readonly", "required"],
"priority": 10
}
]
}
Environments (like styles.json responsive environments):
{
"environments": {
"node": {
"moduleSystem": "CommonJS",
"globals": ["process", "Buffer"]
},
"browser": {
"moduleSystem": "ES2015",
"globals": ["window", "document"]
}
}
}
7. Practical Use Cases
- Component Libraries: Define all component prop types in JSON
- API Contracts: Generate TypeScript types from API schemas
- Configuration: Type-safe config objects defined declaratively
- Theme Systems: Type definitions for theme tokens and variants
- State Management: Action and state type definitions
8. Future Enhancements
- Validation: JSON Schema validation for types.json
- Visualization: Storybook panel to explore type relationships (like StylesPanel)
- Code Generation: Generate not just types but implementation stubs
- Documentation: Auto-generate docs from type definitions
- Migration Tools: Convert existing .ts files to types.json
Example Files
See the demonstration in:
This mirrors the existing pattern:
Conclusion
This pattern demonstrates that any code abstraction can be represented declaratively in JSON when you:
- Define a clear schema
- Build a compiler to transform it
- Support composition and rules
- Enable multi-target output
- Provide tooling for debugging/visualization
The same pattern used for CSS → styles.json applies perfectly to TypeScript → types.json.