11# Type Printer Component
22
33<primary-label ref =" printer-component " />
4+ <link-summary >
5+ Turns a ` TypeLang\Type\* ` AST back into a type string, either as a
6+ high-fidelity TypeLang rendering or as a PHP-compatible one.
7+ </link-summary >
48<show-structure for =" chapter " depth =" 2 " />
59
6- The printer package is responsible for visualizing the AST as string
7- formats.
10+ The printer component is the inverse of the [ parser] ( parser.md ) : where the
11+ parser turns a type string into an <tooltip term =" AST " >AST</tooltip >, the
12+ printer turns that AST back into a string. It walks a
13+ ` TypeLang\Type\TypeNode ` and renders every node — a union, a shape, a
14+ conditional type — into readable text.
15+
16+ It ships with two printers that render the very same AST differently:
17+
18+ <deflist >
19+ <def title="TypeLang\Printer\PrettyTypePrinter">
20+ Renders the type as faithfully as possible, preserving every detail
21+ the AST carries — shapes, generics, conditional types and all. See
22+ <a href="pretty-printer.md">Pretty Printer</a>.
23+ </def>
24+ <def title="TypeLang\Printer\NativeTypePrinter">
25+ Renders the closest type PHP itself would accept, collapsing anything
26+ without a native equivalent down to a supported approximation. See
27+ <a href="native-printer.md">Native Printer</a>.
28+ </def>
29+ </deflist >
830
931## Installation
1032
@@ -19,153 +41,139 @@ formats.
1941* ` PHP >= 8.4 `
2042* ` ext-mbstring ` <sup >optional</sup >
2143
22- ## Usage
23-
24- Package supports two printer classes.
25-
26- <deflist >
27- <def title="TypeLang\Printer\PrettyPrinter">
28- Used to display types as accurately as possible.
29- </def>
30- <def title="TypeLang\Printer\NativeTypePrinter">
31- Used to display types compatible with PHP.
32- </def>
33- </deflist >
34-
35- Any printer implements the ` TypeLang\Printer\PrinterInterface ` interface, which
36- contains an ` print() ` method for displaying ASTs as formatted strings.
44+ ## Quick Start
3745
38- ### Shapes
46+ Every printer implements ` TypeLang\Printer\TypePrinterInterface ` , a single
47+ ` print() ` method that takes a ` TypeNode ` and returns its string form. The AST
48+ usually comes straight from the [ parser] ( parser.md ) , but any hand-built or
49+ rewritten ` TypeLang\Type\* ` node graph prints just as well.
3950
4051<tabs >
41- <tab title =" PrettyPrinter " >
52+ <tab title =" PrettyTypePrinter " >
4253
4354``` php
44- $parser = new TypeLang\Parser\TypeParser() ;
45- $printer = new TypeLang\Printer\PrettyTypePrinter() ;
55+ use TypeLang\Parser\TypeParser;
56+ use TypeLang\Printer\PrettyTypePrinter;
4657
47- $result = $parser->parse(<<<'PHP'
48- object{key: type, some: (list<T >|some<T >),
49- ...<non-empty-string , int >}
50- PHP);
58+ $type = new TypeParser()->parse('non-empty-list<positive-int >|null');
5159
52- echo $printer ->print($result );
60+ echo new PrettyTypePrinter() ->print($type );
5361```
5462
55- > Displays types as accurately as possible.
56- > ``` php
57- > object{
58- > key: type,
59- > some: list<T >|some<T >,
60- > ...<non-empty-string , int >
61- > }
63+ > Renders the type exactly as written, only normalizing whitespace.
64+ > ```
65+ > non-empty-list<positive-int> | null
6266> ```
6367
6468</tab>
6569<tab title="NativeTypePrinter">
6670
6771```php
68- $parser = new TypeLang\Parser\TypeParser() ;
69- $printer = new TypeLang\Printer\NativeTypePrinter() ;
72+ use TypeLang\Parser\TypeParser;
73+ use TypeLang\Printer\NativeTypePrinter;
7074
71- $result = $parser->parse(<<<'PHP'
72- object{key: type, some: (list<T >|some<T >),
73- ...<non-empty-string , int >}
74- PHP);
75+ $type = new TypeParser()->parse('non-empty-list<positive-int>|null');
7576
76- echo $printer ->print($result );
77+ echo new NativeTypePrinter() ->print($type );
7778```
7879
79- > Displays types that are compatible with PHP.
80- > ``` php
81- > object
80+ > Collapses everything down to a type PHP would accept: ` non-empty-list<…> `
81+ > becomes ` array ` .
82+ > ```
83+ > array|null
8284> ```
8385
8486</tab>
8587</tabs>
8688
87- ### Callables
89+ <tip>
90+ A printer is stateless between calls and cheap to keep around. Construct it
91+ once — with whatever formatting options you need — and reuse the instance
92+ across the application rather than building a new one per type.
93+ </tip>
8894
89- <tabs >
90- <tab title =" PrettyPrinter" >
95+ ## Choosing a Printer
9196
92- ```php
93- $parser = new TypeLang\Parser\TypeParser();
94- $printer = new TypeLang\Printer\PrettyTypePrinter();
97+ Both printers accept the same AST; they differ only in what they render.
9598
96- $result = $parser->parse(<<<'PHP'
97- callable(...A & $a)|callable(B & ...$b)
98- PHP);
99+ | | [Pretty](pretty-printer.md) | [Native](native-printer.md) |
100+ |------------------------|-----------------------------|-----------------------------|
101+ | **Goal** | faithful, human-readable | valid PHP syntax |
102+ | `array{id: int}` | `array{id: int}` | `array` |
103+ | `int[]` | `int[]` | `iterable` |
104+ | `positive-int` | `positive-int` | `int` |
105+ | `Foo::BAR` | `Foo::BAR` | `mixed` |
106+ | `int<0, max>` | `int<0, max>` | `int` |
107+ | `$arg is null ? A : B` | `($arg is null ? A : B)` | `A│B` |
99108
100- echo $printer->print($result);
101- ```
109+ Reach for the **pretty** printer to display a type to a human — an error
110+ message, a generated docblock, a diff — where every detail matters. Reach for
111+ the **native** printer to emit something PHP can actually use — a property
112+ type, a parameter hint, generated code.
102113
103- > Displays types as accurately as possible.
104- > ``` php
105- > callable(A & ...$a)|callable(B & ...$b)
106- > ```
114+ ## Formatting
107115
108- </ tab >
109- < tab title = " NativeTypePrinter " >
116+ Both printers share two constructor arguments, declared on the common
117+ `TypeLang\Printer\TypePrinter` base:
110118
111- ```php
112- $parser = new TypeLang\Parser\TypeParser();
113- $printer = new TypeLang\Printer\NativeTypePrinter();
114-
115- $result = $parser->parse(<<<'PHP'
116- callable(...A & $a)|callable(B & ...$b)
117- PHP);
119+ <deflist>
120+ <def title="newLine">
121+ The line-break string inserted between the lines of a multi-line
122+ rendering. Defaults to <code>"\n"</code>.
123+ </def>
124+ <def title="indention">
125+ The string used for a single indentation level. Defaults to four
126+ spaces.
127+ </def>
128+ </deflist>
118129
119- echo $printer->print($result);
130+ ```php
131+ $printer = new PrettyTypePrinter(
132+ newLine: "\r\n",
133+ indention: "\t",
134+ );
120135```
121136
122- > Displays types that are compatible with PHP.
123- > ``` php
124- > callable
125- > ```
126-
127- </tab >
128- </tabs >
137+ <note >
138+ The <code >NativeTypePrinter</code > takes its type aliases as the
139+ <b >first</b > constructor argument, so pass <code >newLine</code > and
140+ <code >indention</code > by name — see <a href =" native-printer.md " >Native
141+ Printer</a >.
142+ </note >
129143
130- ### Conditional
144+ ## Error Handling
131145
132- <tabs >
133- <tab title =" PrettyPrinter" >
146+ A printer only knows how to render the nodes that make up a valid type. If it
147+ is handed a node it cannot render — a malformed, hand-built AST, or a node
148+ kind it does not support — it throws a
149+ ` TypeLang\Printer\Exception\NonPrintableNodeException ` .
134150
135151``` php
136- $parser = new TypeLang\Parser\TypeParser();
137- $printer = new TypeLang\Printer\PrettyTypePrinter();
138-
139- $result = $parser->parse(<<<'PHP'
140- $arg is null ? non-empty-string : int<0 , max >
141- PHP);
142-
143- echo $printer->print($result);
152+ try {
153+ echo $printer->print($node);
154+ } catch (\TypeLang\Printer\Exception\PrinterExceptionInterface $e) {
155+ // Every exception the component throws implements this interface.
156+ }
144157```
145158
146- > Displays types as accurately as possible.
147- > ``` php
148- > ($arg is null ? non-empty-string : int<0 , max >)
149- > ```
159+ An AST produced by the [ parser] ( parser.md ) is always printable, so this only
160+ becomes a concern when constructing or rewriting the node graph by hand.
150161
151- </tab >
152- <tab title =" NativeTypePrinter" >
162+ ## What's Next
153163
154- ```php
155- $parser = new TypeLang\Parser\TypeParser();
156- $printer = new TypeLang\Printer\NativeTypePrinter();
164+ <deflist >
165+ <def title =" Pretty Printer " >
157166
158- $result = $parser->parse(<<<'PHP'
159- $arg is null ? non-empty-string : int< 0 , max >
160- PHP);
167+ The high-fidelity renderer and its formatting options — union and
168+ intersection spacing, callable return types, and multi-line shapes. See
169+ [ ] ( pretty-printer.md ) .
161170
162- echo $printer->print($result);
163- ```
171+ </ def >
172+ < def title = " Native Printer " >
164173
165- > Displays types that are compatible with PHP.
166- > ``` php
167- > string|int
168- > ```
174+ The PHP-compatible renderer: how each unsupported construct is approximated,
175+ and the built-in and custom type aliases it applies. See
176+ [ ] ( native-printer.md ) .
169177
170- </tab >
171- </tabs >
178+ </def >
179+ </deflist >
0 commit comments