Commit c375f50
Breaking: Add zero-cost TypeScript node type narrowing layer (#205)
## Summary
This PR introduces a comprehensive TypeScript type narrowing system for
CSS AST nodes, enabling type-safe node handling without runtime
overhead. The implementation provides both type predicate functions and
a discriminated union type for exhaustive narrowing patterns.
## Key Changes
- **New `src/node-types.ts`**: Defines 39 specialized node interfaces
that extend `CSSNode` with precise property types, removing spurious
`undefined` values from type-specific properties
- Each interface overrides property types to reflect what a specific
node type actually returns
- Examples: `DeclarationNode.property` is `string` (not `string |
undefined`), `DimensionNode.unit` is `string` (not `string | undefined`)
- **Type predicate functions**: 39 individual `is_*()` functions for
runtime type narrowing
- Each compiles to a single integer comparison (zero heap allocation)
- All are individually tree-shakeable named exports
- Enable idiomatic TypeScript patterns: `if (is_declaration(node)) {
node.property /* string */ }`
- **`AnyCssNode` discriminated union**: Enables exhaustive switch-based
narrowing without explicit type predicates
- Allows automatic type narrowing in switch statements based on
`node.type`
- Useful for walk callbacks and visitor patterns
- **Comprehensive test suite** (`src/node-types.test.ts`):
- Runtime behavior tests for all major type predicates
- Compile-time type assertion tests using `expectTypeOf` to verify
narrowing works correctly
- Tests for selector subtypes and complex nested structures
- **Updated exports** in `src/index.ts`: All node type interfaces and
predicate functions are now publicly exported
- **Updated `src/walk.ts`**: Walk callback parameter type changed from
`CSSNode` to `AnyCssNode` for better type inference in user code
- **Updated `src/constants.ts`**: Added missing `UNICODE_RANGE` export
## Implementation Details
- All interfaces are erased at compile time — zero bytes in the JS
output
- Type predicates compile to single integer comparisons with no runtime
overhead
- The design follows TypeScript best practices for discriminated unions
and type guards
- Comprehensive documentation in comments explains usage patterns and
benefits
https://claude.ai/code/session_01AutHjiFtdrfyBLJ64JwXnM
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 4064188 commit c375f50
File tree
22 files changed
+2445
-1423
lines changed- src
22 files changed
+2445
-1423
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
94 | 94 | | |
95 | 95 | | |
96 | 96 | | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | 97 | | |
103 | 98 | | |
104 | 99 | | |
| |||
902 | 897 | | |
903 | 898 | | |
904 | 899 | | |
905 | | - | |
906 | | - | |
907 | | - | |
908 | | - | |
909 | | - | |
910 | | - | |
911 | | - | |
912 | | - | |
913 | | - | |
914 | | - | |
915 | | - | |
916 | | - | |
917 | | - | |
918 | | - | |
919 | | - | |
920 | | - | |
921 | | - | |
922 | | - | |
923 | | - | |
924 | | - | |
925 | | - | |
926 | | - | |
927 | | - | |
928 | | - | |
929 | | - | |
930 | | - | |
931 | | - | |
932 | | - | |
933 | | - | |
934 | | - | |
935 | | - | |
936 | | - | |
937 | | - | |
938 | | - | |
939 | | - | |
940 | | - | |
941 | | - | |
942 | | - | |
943 | | - | |
944 | | - | |
945 | | - | |
946 | | - | |
947 | 900 | | |
948 | 901 | | |
949 | 902 | | |
| |||
0 commit comments