[Typia] 15,000x faster TypeScript Validator and its histories
Series of TypeScript Compiler based Libraries
- I made 1,000x faster TypeScript validator library
- I made 10x faster JSON.stringify() functions, even type safe
- Nestia, super-fast validator decorators for NestJS
- Automatic React components generator from TypeScript type
Renamed to Typia
Hello, I’m developer of typescript-json
typia
.
In nowadays, I’ve renamed typescript-json
library to typia, because the word “JSON” no more can represent it. Key feature of typia
had been changed from faster JSON stringify function to superfast validation function. Furthermore, typia
has started supporting Protocol Buffer (in alpha version, not regular feature yet).
Introducing such package renaming from typescript-json
to typia
, I will tell you which changes had been occured during six months. Lots of interesting features and improvements have been happened.
What
typia
is:
1234567891011 <span class="c1">// RUNTIME VALIDATORS</span><span class="k">export</span> <span class="kd">function</span> <span class="k">is</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">unknown</span> <span class="o">|</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">input</span> <span class="k">is</span> <span class="nx">T</span><span class="p">;</span> <span class="c1">// returns boolean</span><span class="k">export</span> <span class="kd">function</span> <span class="nx">assert</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">unknown</span> <span class="o">|</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">T</span><span class="p">;</span> <span class="c1">// throws TypeGuardError</span><span class="k">export</span> <span class="kd">function</span> <span class="nx">validate</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">unknown</span> <span class="o">|</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">IValidation</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">;</span> <span class="c1">// detailed</span> <span class="c1">// STRICT VALIDATORS</span><span class="k">export</span> <span class="kd">function</span> <span class="nx">equals</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">unknown</span> <span class="o">|</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">input</span> <span class="k">is</span> <span class="nx">T</span><span class="p">;</span><span class="k">export</span> <span class="kd">function</span> <span class="nx">assertEquals</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">unknown</span> <span class="o">|</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">T</span><span class="p">;</span><span class="k">export</span> <span class="kd">function</span> <span class="nx">validateEquals</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">unknown</span> <span class="o">|</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">IValidation</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">;</span> <span class="c1">// JSON</span><span class="k">export</span> <span class="kd">function</span> <span class="nx">application</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">():</span> <span class="nx">IJsonApplication</span><span class="p">;</span> <span class="c1">// JSON schema</span><span class="k">export</span> <span class="kd">function</span> <span class="nx">assertParse</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="kr">string</span><span class="p">):</span> <span class="nx">T</span><span class="p">;</span> <span class="c1">// type safe parser</span><span class="k">export</span> <span class="kd">function</span> <span class="nx">assertStringify</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">T</span><span class="p">):</span> <span class="kr">string</span><span class="p">;</span> <span class="c1">// safe and faster</span> <span class="c1">// +) isParse, validateParse </span> <span class="c1">// +) stringify, isStringify, validateStringify</span>
typia is a transformer library of TypeScript, supporting below features:
- Super-fast Runtime Validators
- Safe JSON parse and fast stringify functions
- JSON schema generator
All functions in
typia
require only one line. You don’t need any extra dedication like JSON schema definitions or decorator function calls. Just calltypia
function with only one line liketypia.assert<T>(input)
.Also, as
typia
performs AOT (Ahead of Time) compilation skill, its performance is much faster than other competitive libaries. For an example, when comparing validate functionis()
with other competitive libraries,typia
is maximum 15,000x times faster thanclass-validator
.
Became 15,000x faster runtime validator library
1 2 3 4 5 |
<span class="c1">// TypeBox was faster than Typia in here `ObjectSimple` case</span> <span class="k">export</span> <span class="kd">type</span> <span class="nx">ObjectSimple</span> <span class="o">=</span> <span class="nx">ObjectSimple</span><span class="p">.</span><span class="nx">IBox3D</span><span class="p">;</span> <span class="k">export</span> <span class="k">namespace</span> <span class="nx">ObjectSimple</span> <span class="p">{</span> <span class="k">export</span> <span class="kr">interface</span> <span class="nx">IBox3D</span> <span class="p">{</span> <span class="nl">scale</span><span class="p">:</span> <span class="nx">IPoint3D</span><span class="p">;</span> <span class="nl">position</span><span class="p">:</span> <span class="nx">IPoint3D</span><span class="p">;</span> <span class="nl">rotate</span><span class="p">:</span> <span class="nx">IPoint3D</span><span class="p">;</span> <span class="nl">pivot</span><span class="p">:</span> <span class="nx">IPoint3D</span><span class="p">;</span> <span class="p">}</span> <span class="k">export</span> <span class="kr">interface</span> <span class="nx">IPoint3D</span> <span class="p">{</span> <span class="nl">x</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span> <span class="nl">y</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span> <span class="nl">z</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> |
Do you remember? About a month ago, I wrote an article about TypeBox and said “I found faster vlidator library than me (in some cases)”. During a month, I’d tried to understand and study the reason why.
During the studies, I found the reason why. The secret was on inlining.
When validating an instance type, typia
generates functions per object type. Therefore, when a type is related with 8 object types, 8 internal functions would be generated.
However, typebox
let user to decide whether to make validate function for an object type or not (by $recursiveRef
flag).
Benchmark code about
typebox
was written bytypebox
author himself.
Looking at below code, you may understand what the inlining means and how typia
and typebox
are different. typia
is generating functions per object type (Box3D
and Point3d
), but typebox
does not make any internal function but inline all of them.
1 2 3 4 5 6 |
<span class="c1">// COMPILED VALIDATION CODE OF TYPIA</span> <span class="kd">const</span> <span class="k">is</span> <span class="o">=</span> <span class="p">(</span><span class="nx">input</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="kd">const</span> <span class="nx">$io0</span> <span class="o">=</span> <span class="p">(</span><span class="nx">input</span><span class="p">)</span> <span class="o">=></span> <span class="dl">"</span><span class="s2">object</span><span class="dl">"</span> <span class="o">===</span> <span class="k">typeof</span> <span class="nx">input</span><span class="p">.</span><span class="nx">scale</span> <span class="o">&&</span> <span class="kc">null</span> <span class="o">!==</span> <span class="nx">input</span><span class="p">.</span><span class="nx">scale</span> <span class="o">&&</span> <span class="nx">$io1</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">scale</span><span class="p">)</span> <span class="o">&&</span> <span class="dl">"</span><span class="s2">object</span><span class="dl">"</span> <span class="o">===</span> <span class="k">typeof</span> <span class="nx">input</span><span class="p">.</span><span class="nx">position</span> <span class="o">&&</span> <span class="kc">null</span> <span class="o">!==</span> <span class="nx">input</span><span class="p">.</span><span class="nx">position</span> <span class="o">&&</span> <span class="nx">$io1</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">position</span><span class="p">)</span> <span class="o">&&</span> <span class="dl">"</span><span class="s2">object</span><span class="dl">"</span> <span class="o">===</span> <span class="k">typeof</span> <span class="nx">input</span><span class="p">.</span><span class="nx">rotate</span> <span class="o">&&</span> <span class="kc">null</span> <span class="o">!==</span> <span class="nx">input</span><span class="p">.</span><span class="nx">rotate</span> <span class="o">&&</span> <span class="nx">$io1</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">rotate</span><span class="p">)</span> <span class="o">&&</span> <span class="dl">"</span><span class="s2">object</span><span class="dl">"</span> <span class="o">===</span> <span class="k">typeof</span> <span class="nx">input</span><span class="p">.</span><span class="nx">pivot</span> <span class="o">&&</span> <span class="kc">null</span> <span class="o">!==</span> <span class="nx">input</span><span class="p">.</span><span class="nx">pivot</span> <span class="o">&&</span> <span class="nx">$io1</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">pivot</span><span class="p">);</span> <span class="kd">const</span> <span class="nx">$io1</span> <span class="o">=</span> <span class="p">(</span><span class="nx">input</span><span class="p">)</span> <span class="o">=></span> <span class="dl">"</span><span class="s2">number</span><span class="dl">"</span> <span class="o">===</span> <span class="k">typeof</span> <span class="nx">input</span><span class="p">.</span><span class="nx">x</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">x</span><span class="p">)</span> <span class="o">&&</span> <span class="nb">isFinite</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">x</span><span class="p">)</span> <span class="o">&&</span> <span class="dl">"</span><span class="s2">number</span><span class="dl">"</span> <span class="o">===</span> <span class="k">typeof</span> <span class="nx">input</span><span class="p">.</span><span class="nx">y</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">y</span><span class="p">)</span> <span class="o">&&</span> <span class="nb">isFinite</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">y</span><span class="p">)</span> <span class="o">&&</span> <span class="dl">"</span><span class="s2">number</span><span class="dl">"</span> <span class="o">===</span> <span class="k">typeof</span> <span class="nx">input</span><span class="p">.</span><span class="nx">z</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">z</span><span class="p">)</span> <span class="o">&&</span> <span class="nb">isFinite</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">z</span><span class="p">);</span> <span class="k">return</span> <span class="dl">"</span><span class="s2">object</span><span class="dl">"</span> <span class="o">===</span> <span class="k">typeof</span> <span class="nx">input</span> <span class="o">&&</span> <span class="kc">null</span> <span class="o">!==</span> <span class="nx">input</span> <span class="o">&&</span> <span class="nx">$io0</span><span class="p">(</span><span class="nx">input</span><span class="p">);</span> <span class="p">};</span> <span class="c1">// COMPILED VALIDATION CODE OF TYPEBOX</span> <span class="kd">function</span> <span class="nx">Check</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">object</span><span class="dl">'</span> <span class="o">&&</span> <span class="nx">value</span> <span class="o">!==</span> <span class="kc">null</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">value</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">scale</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">object</span><span class="dl">'</span> <span class="o">&&</span> <span class="nx">value</span><span class="p">.</span><span class="nx">scale</span> <span class="o">!==</span> <span class="kc">null</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">scale</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">x</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">x</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">y</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">y</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">z</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">scale</span><span class="p">.</span><span class="nx">z</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">position</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">object</span><span class="dl">'</span> <span class="o">&&</span> <span class="nx">value</span><span class="p">.</span><span class="nx">position</span> <span class="o">!==</span> <span class="kc">null</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">position</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">position</span><span class="p">.</span><span class="nx">x</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">position</span><span class="p">.</span><span class="nx">x</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">position</span><span class="p">.</span><span class="nx">y</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">position</span><span class="p">.</span><span class="nx">y</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">position</span><span class="p">.</span><span class="nx">z</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">position</span><span class="p">.</span><span class="nx">z</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">rotate</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">object</span><span class="dl">'</span> <span class="o">&&</span> <span class="nx">value</span><span class="p">.</span><span class="nx">rotate</span> <span class="o">!==</span> <span class="kc">null</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">rotate</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">rotate</span><span class="p">.</span><span class="nx">x</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">rotate</span><span class="p">.</span><span class="nx">x</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">rotate</span><span class="p">.</span><span class="nx">y</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">rotate</span><span class="p">.</span><span class="nx">y</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">rotate</span><span class="p">.</span><span class="nx">z</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">rotate</span><span class="p">.</span><span class="nx">z</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">pivot</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">object</span><span class="dl">'</span> <span class="o">&&</span> <span class="nx">value</span><span class="p">.</span><span class="nx">pivot</span> <span class="o">!==</span> <span class="kc">null</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">Array</span><span class="p">.</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">pivot</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">pivot</span><span class="p">.</span><span class="nx">x</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">pivot</span><span class="p">.</span><span class="nx">x</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">pivot</span><span class="p">.</span><span class="nx">y</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">pivot</span><span class="p">.</span><span class="nx">y</span><span class="p">))</span> <span class="o">&&</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">value</span><span class="p">.</span><span class="nx">pivot</span><span class="p">.</span><span class="nx">z</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">number</span><span class="dl">'</span> <span class="o">&&</span> <span class="o">!</span><span class="nb">isNaN</span><span class="p">(</span><span class="nx">value</span><span class="p">.</span><span class="nx">pivot</span><span class="p">.</span><span class="nx">z</span><span class="p">))</span> <span class="p">)</span> <span class="p">}</span> |
As you know, function calls have their own cost. Therefore, inlining may be faster than function call. However, inlining is not always faster then function call, and there is a section where performance is reversed between function calls and inlining.
typebox
let users to determine by themselves through JSON schema definition, but typia
can’t do it, because typia
generates runtime validator function automatically by only one line statement; typia.assert<T>(input)
.
1 2 3 4 5 6 7 8 9 |
<span class="c1">// CODE OF TYPIA</span> <span class="k">import</span> <span class="nx">typia</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">typia</span><span class="dl">"</span><span class="p">;</span> <span class="nx">typia</span><span class="p">.</span><span class="k">is</span><span class="o"><</span><span class="nx">ObjectSimple</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">);</span> <span class="c1">// CODE OF TYPEBOX</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">Type</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@sinclair/typebox</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">TypeCompiler</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@sinclair/typebox/compiler</span><span class="dl">"</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">Point3D</span> <span class="o">=</span> <span class="nx">Type</span><span class="p">.</span><span class="nb">Object</span><span class="p">({</span> <span class="na">x</span><span class="p">:</span> <span class="nx">Type</span><span class="p">.</span><span class="nb">Number</span><span class="p">(),</span> <span class="na">y</span><span class="p">:</span> <span class="nx">Type</span><span class="p">.</span><span class="nb">Number</span><span class="p">(),</span> <span class="na">z</span><span class="p">:</span> <span class="nx">Type</span><span class="p">.</span><span class="nb">Number</span><span class="p">(),</span> <span class="p">});</span> <span class="kd">const</span> <span class="nx">Box3D</span> <span class="o">=</span> <span class="nx">Type</span><span class="p">.</span><span class="nb">Object</span><span class="p">({</span> <span class="na">scale</span><span class="p">:</span> <span class="nx">Point3D</span><span class="p">,</span> <span class="na">position</span><span class="p">:</span> <span class="nx">Point3D</span><span class="p">,</span> <span class="na">rotate</span><span class="p">:</span> <span class="nx">Point3D</span><span class="p">,</span> <span class="na">pivot</span><span class="p">:</span> <span class="nx">Point3D</span><span class="p">,</span> <span class="p">});</span> <span class="nx">TypeBoxObjectSimple</span> <span class="o">=</span> <span class="nx">TypeCompiler</span><span class="p">.</span><span class="nx">Compile</span><span class="p">(</span><span class="nx">Box3D</span><span class="p">);</span> <span class="nx">TypeBoxObjectSimple</span><span class="p">.</span><span class="nx">Check</span><span class="p">(</span><span class="nx">input</span><span class="p">);</span> |
Therefore, it is necessary for me to compare the pros and cons of function call and inlining, and to select an algorithm at an appropriate level. I’d changed typia
code to use such inlining skill in special cases and the result was typia
became 15,000x faster validator than class-validator
.
From now on, typia
is the fastest runtime validator library.
Measured on Intel i5-1135g7, Surface Pro 8
New Features
More Types
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<span class="c1">// REST ARRAY TYPE IN TUPLE TYPE</span> <span class="kd">type</span> <span class="nx">RestArrayInTuple</span> <span class="o">=</span> <span class="p">[</span><span class="nx">boolean</span><span class="p">,</span> <span class="kr">number</span><span class="p">,</span> <span class="p">...</span><span class="kr">string</span><span class="p">[]];</span> <span class="c1">// BUILT-IN CLASS TYPES</span> <span class="kd">type</span> <span class="nx">BuildInClassTypes</span> <span class="o">=</span> <span class="nb">Date</span> <span class="o">|</span> <span class="nb">Uint8Array</span> <span class="o">|</span> <span class="p">{...}</span> <span class="o">|</span> <span class="nx">Buffer</span> <span class="o">|</span> <span class="nb">DataView</span><span class="p">;</span> <span class="c1">// TEMPLATE TYPES</span> <span class="kr">interface</span> <span class="nx">Templates</span> <span class="p">{</span> <span class="nl">prefix</span><span class="p">:</span> <span class="s2">`prefix_</span><span class="p">${</span><span class="kr">string</span> <span class="o">|</span> <span class="kr">number</span> <span class="o">|</span> <span class="nx">boolean</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span> <span class="nl">postfix</span><span class="p">:</span> <span class="s2">`</span><span class="p">${</span><span class="kr">string</span> <span class="o">|</span> <span class="kr">number</span> <span class="o">|</span> <span class="nx">boolean</span><span class="p">}</span><span class="s2">_postfix`</span><span class="p">;</span> <span class="nl">middle</span><span class="p">:</span> <span class="s2">`the_</span><span class="p">${</span><span class="kr">number</span> <span class="o">|</span> <span class="nx">boolean</span><span class="p">}</span><span class="s2">_value`</span><span class="p">;</span> <span class="nl">mixed</span><span class="p">:</span> <span class="o">|</span> <span class="s2">`the_</span><span class="p">${</span><span class="kr">number</span> <span class="o">|</span> <span class="dl">"</span><span class="s2">A</span><span class="dl">"</span> <span class="o">|</span> <span class="dl">"</span><span class="s2">B</span><span class="dl">"</span><span class="p">}</span><span class="s2">_value`</span> <span class="o">|</span> <span class="nx">boolean</span> <span class="o">|</span> <span class="kr">number</span><span class="p">;</span> <span class="nl">ipv4</span><span class="p">:</span> <span class="s2">`</span><span class="p">${</span><span class="kr">number</span><span class="p">}</span><span class="s2">.</span><span class="p">${</span><span class="kr">number</span><span class="p">}</span><span class="s2">.</span><span class="p">${</span><span class="kr">number</span><span class="p">}</span><span class="s2">.</span><span class="p">${</span><span class="kr">number</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span> <span class="nl">email</span><span class="p">:</span> <span class="s2">`</span><span class="p">${</span><span class="kr">string</span><span class="p">}</span><span class="s2">@</span><span class="p">${</span><span class="kr">string</span><span class="p">}</span><span class="s2">.</span><span class="p">${</span><span class="kr">string</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span> <span class="p">}</span> <span class="c1">//----</span> <span class="c1">// JUST CRAZY TYPE</span> <span class="c1">//----</span> <span class="kd">type</span> <span class="nx">Join</span><span class="o"><</span><span class="nx">K</span><span class="p">,</span> <span class="nx">P</span><span class="o">></span> <span class="o">=</span> <span class="nx">K</span> <span class="kd">extends</span> <span class="kr">string</span> <span class="o">|</span> <span class="kr">number</span> <span class="p">?</span> <span class="nx">P</span> <span class="kd">extends</span> <span class="kr">string</span> <span class="o">|</span> <span class="kr">number</span> <span class="p">?</span> <span class="s2">`</span><span class="p">${</span><span class="nx">K</span><span class="p">}${</span><span class="dl">""</span> <span class="kd">extends</span> <span class="nx">P</span> <span class="p">?</span> <span class="dl">""</span> <span class="p">:</span> <span class="dl">"</span><span class="s2">.</span><span class="dl">"</span><span class="p">}${</span><span class="nx">P</span><span class="p">}</span><span class="s2">`</span> <span class="p">:</span> <span class="nx">never</span> <span class="p">:</span> <span class="nx">never</span><span class="p">;</span> <span class="kd">type</span> <span class="nx">Prev</span> <span class="o">=</span> <span class="p">[</span><span class="nx">never</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">];</span> <span class="kd">type</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">O</span><span class="p">,</span> <span class="nx">F</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">^%#&[email protected]</span><span class="dl">"</span><span class="p">,</span> <span class="nx">D</span> <span class="kd">extends</span> <span class="kr">number</span> <span class="o">=</span> <span class="mi">4</span><span class="o">></span> <span class="o">=</span> <span class="p">[</span><span class="nx">D</span><span class="p">]</span> <span class="kd">extends</span> <span class="p">[</span> <span class="nx">never</span><span class="p">,</span> <span class="p">]</span> <span class="p">?</span> <span class="nx">never</span> <span class="p">:</span> <span class="nx">O</span> <span class="kd">extends</span> <span class="nx">object</span> <span class="p">?</span> <span class="p">{</span> <span class="p">[</span><span class="nx">K</span> <span class="k">in</span> <span class="kr">keyof</span> <span class="nx">O</span><span class="p">]</span><span class="o">-</span><span class="p">?:</span> <span class="nx">O</span><span class="p">[</span><span class="nx">K</span><span class="p">]</span> <span class="kd">extends</span> <span class="nx">F</span> <span class="p">?</span> <span class="nx">never</span> <span class="p">:</span> <span class="nx">Join</span><span class="o"><</span><span class="nx">K</span><span class="p">,</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">O</span><span class="p">[</span><span class="nx">K</span><span class="p">],</span> <span class="nx">F</span><span class="p">,</span> <span class="nx">Prev</span><span class="p">[</span><span class="nx">D</span><span class="p">]</span><span class="o">>></span><span class="p">;</span> <span class="p">}[</span><span class="kr">keyof</span> <span class="nx">O</span><span class="p">]</span> <span class="p">:</span> <span class="dl">""</span><span class="p">;</span> <span class="kd">type</span> <span class="nx">TypeOfPath</span><span class="o"><</span> <span class="nx">Schema</span> <span class="kd">extends</span> <span class="p">{</span> <span class="p">[</span><span class="na">k</span><span class="p">:</span> <span class="kr">string</span><span class="p">]:</span> <span class="kr">any</span> <span class="p">},</span> <span class="nx">S</span> <span class="kd">extends</span> <span class="kr">string</span><span class="p">,</span> <span class="nx">D</span> <span class="kd">extends</span> <span class="kr">number</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="o">></span> <span class="o">=</span> <span class="p">[</span><span class="nx">D</span><span class="p">]</span> <span class="kd">extends</span> <span class="p">[</span><span class="nx">never</span><span class="p">]</span> <span class="p">?</span> <span class="nx">never</span> <span class="p">:</span> <span class="nx">S</span> <span class="kd">extends</span> <span class="s2">`</span><span class="p">${</span><span class="nx">infer</span> <span class="nx">T</span><span class="p">}</span><span class="s2">.</span><span class="p">${</span><span class="nx">infer</span> <span class="nx">U</span><span class="p">}</span><span class="s2">`</span> <span class="p">?</span> <span class="nx">TypeOfPath</span><span class="o"><</span><span class="nx">Schema</span><span class="p">[</span><span class="nx">T</span><span class="p">],</span> <span class="nx">U</span><span class="p">,</span> <span class="nx">Prev</span><span class="p">[</span><span class="nx">D</span><span class="p">]</span><span class="o">></span> <span class="p">:</span> <span class="nx">Schema</span><span class="p">[</span><span class="nx">S</span><span class="p">];</span> <span class="kd">const</span> <span class="nx">FILTER_OPERATION_MAPPING_STRING_TO_STRING</span> <span class="o">=</span> <span class="p">{</span> <span class="na">like</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="na">notLike</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="na">substring</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span> <span class="na">startsWith</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span> <span class="na">endsWith</span><span class="p">:</span> <span class="mi">6</span><span class="p">,</span> <span class="p">};</span> <span class="kd">const</span> <span class="nx">FILTER_CONDITION_MAPPING</span> <span class="o">=</span> <span class="p">{</span> <span class="na">or</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="na">and</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="na">not</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span> <span class="p">};</span> <span class="kd">type</span> <span class="nx">ValueType</span> <span class="o">=</span> <span class="o">|</span> <span class="dl">"</span><span class="s2">stringToString</span><span class="dl">"</span> <span class="o">|</span> <span class="dl">"</span><span class="s2">stringToNumber</span><span class="dl">"</span> <span class="o">|</span> <span class="dl">"</span><span class="s2">stringOrNumber</span><span class="dl">"</span> <span class="o">|</span> <span class="dl">"</span><span class="s2">numberArray</span><span class="dl">"</span> <span class="o">|</span> <span class="dl">"</span><span class="s2">array</span><span class="dl">"</span><span class="p">;</span> <span class="kd">type</span> <span class="nx">PathType</span><span class="o"><</span> <span class="nx">TableSchema</span> <span class="kd">extends</span> <span class="p">{</span> <span class="p">[</span><span class="na">k</span><span class="p">:</span> <span class="kr">string</span><span class="p">]:</span> <span class="kr">any</span> <span class="p">}</span> <span class="o">|</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="nx">ValueType</span><span class="p">,</span> <span class="nx">Columns</span> <span class="kd">extends</span> <span class="o">|</span> <span class="nb">Array</span><span class="o"><</span> <span class="nx">TableSchema</span> <span class="kd">extends</span> <span class="kc">undefined</span> <span class="p">?</span> <span class="kr">string</span> <span class="p">:</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">TableSchema</span><span class="o">></span> <span class="o">></span> <span class="o">|</span> <span class="kc">undefined</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">ColumnsExclude</span> <span class="kd">extends</span> <span class="o">|</span> <span class="nb">Array</span><span class="o"><</span> <span class="nx">TableSchema</span> <span class="kd">extends</span> <span class="kc">undefined</span> <span class="p">?</span> <span class="kr">string</span> <span class="p">:</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">TableSchema</span><span class="o">></span> <span class="o">></span> <span class="o">|</span> <span class="kc">undefined</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">,</span> <span class="o">></span> <span class="o">=</span> <span class="nx">Exclude</span><span class="o"><</span> <span class="nx">Columns</span> <span class="kd">extends</span> <span class="kr">any</span><span class="p">[]</span> <span class="p">?</span> <span class="nx">Columns</span> <span class="kd">extends</span> <span class="nb">Array</span><span class="o"><</span><span class="nx">infer</span> <span class="nx">T</span><span class="o">></span> <span class="p">?</span> <span class="nx">T</span> <span class="p">:</span> <span class="nx">never</span> <span class="p">:</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="dl">"</span><span class="s2">stringToString</span><span class="dl">"</span> <span class="p">?</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">TableSchema</span><span class="p">,</span> <span class="kr">number</span> <span class="o">|</span> <span class="nx">boolean</span><span class="o">></span> <span class="p">:</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="dl">"</span><span class="s2">stringToNumber</span><span class="dl">"</span> <span class="p">?</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">TableSchema</span><span class="p">,</span> <span class="kr">string</span> <span class="o">|</span> <span class="nx">boolean</span><span class="o">></span> <span class="p">:</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">TableSchema</span><span class="o">></span><span class="p">,</span> <span class="nx">ColumnsExclude</span> <span class="kd">extends</span> <span class="nb">Array</span><span class="o"><</span><span class="nx">infer</span> <span class="nx">T</span><span class="o">></span> <span class="p">?</span> <span class="nx">T</span> <span class="p">:</span> <span class="kc">undefined</span> <span class="o">></span><span class="p">;</span> <span class="kd">type</span> <span class="nx">FilterBy</span><span class="o"><</span> <span class="nx">Operations</span> <span class="kd">extends</span> <span class="p">{</span> <span class="p">[</span><span class="na">k</span><span class="p">:</span> <span class="kr">string</span><span class="p">]:</span> <span class="kr">any</span> <span class="p">},</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="nx">ValueType</span><span class="p">,</span> <span class="nx">TableSchema</span> <span class="kd">extends</span> <span class="p">{</span> <span class="p">[</span><span class="na">k</span><span class="p">:</span> <span class="kr">string</span><span class="p">]:</span> <span class="kr">any</span> <span class="p">}</span> <span class="o">|</span> <span class="kc">undefined</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">Columns</span> <span class="kd">extends</span> <span class="o">|</span> <span class="nb">Array</span><span class="o"><</span> <span class="nx">TableSchema</span> <span class="kd">extends</span> <span class="kc">undefined</span> <span class="p">?</span> <span class="kr">string</span> <span class="p">:</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">TableSchema</span><span class="o">></span> <span class="o">></span> <span class="o">|</span> <span class="kc">undefined</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">ColumnsExclude</span> <span class="kd">extends</span> <span class="o">|</span> <span class="nb">Array</span><span class="o"><</span> <span class="nx">TableSchema</span> <span class="kd">extends</span> <span class="kc">undefined</span> <span class="p">?</span> <span class="kr">string</span> <span class="p">:</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">TableSchema</span><span class="o">></span> <span class="o">></span> <span class="o">|</span> <span class="kc">undefined</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">Path</span> <span class="kd">extends</span> <span class="nx">PathType</span><span class="o"><</span> <span class="nx">TableSchema</span><span class="p">,</span> <span class="nx">Type</span><span class="p">,</span> <span class="nx">Columns</span><span class="p">,</span> <span class="nx">ColumnsExclude</span> <span class="o">></span> <span class="o">=</span> <span class="nx">PathType</span><span class="o"><</span><span class="nx">TableSchema</span><span class="p">,</span> <span class="nx">Type</span><span class="p">,</span> <span class="nx">Columns</span><span class="p">,</span> <span class="nx">ColumnsExclude</span><span class="o">></span><span class="p">,</span> <span class="o">></span> <span class="o">=</span> <span class="nx">TableSchema</span> <span class="kd">extends</span> <span class="kc">undefined</span> <span class="p">?</span> <span class="p">{</span> <span class="na">operation</span><span class="p">:</span> <span class="kr">keyof</span> <span class="nx">Operations</span><span class="p">;</span> <span class="nl">column</span><span class="p">:</span> <span class="nx">Columns</span> <span class="kd">extends</span> <span class="kr">any</span><span class="p">[]</span> <span class="p">?</span> <span class="nx">Columns</span> <span class="kd">extends</span> <span class="nb">Array</span><span class="o"><</span><span class="nx">infer</span> <span class="nx">T</span><span class="o">></span> <span class="p">?</span> <span class="nx">T</span> <span class="p">:</span> <span class="nx">never</span> <span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="nl">value</span><span class="p">:</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="dl">"</span><span class="s2">numberArray</span><span class="dl">"</span> <span class="p">?</span> <span class="p">[</span><span class="kr">string</span> <span class="o">|</span> <span class="kr">number</span><span class="p">,</span> <span class="kr">string</span> <span class="o">|</span> <span class="kr">number</span><span class="p">]</span> <span class="p">:</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="dl">"</span><span class="s2">array</span><span class="dl">"</span> <span class="p">?</span> <span class="nb">Array</span><span class="o"><</span><span class="kr">string</span> <span class="o">|</span> <span class="kr">number</span><span class="o">></span> <span class="p">:</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="dl">"</span><span class="s2">stringToString</span><span class="dl">"</span> <span class="p">?</span> <span class="kr">string</span> <span class="p">:</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="dl">"</span><span class="s2">stringToNumber</span><span class="dl">"</span> <span class="p">?</span> <span class="kr">string</span> <span class="p">:</span> <span class="kr">string</span> <span class="o">|</span> <span class="kr">number</span><span class="p">;</span> <span class="p">}</span> <span class="p">:</span> <span class="p">{</span> <span class="p">[</span><span class="nx">key</span> <span class="k">in</span> <span class="nx">Path</span><span class="p">]:</span> <span class="p">{</span> <span class="na">operation</span><span class="p">:</span> <span class="kr">keyof</span> <span class="nx">Operations</span><span class="p">;</span> <span class="nl">column</span><span class="p">:</span> <span class="nx">Columns</span> <span class="kd">extends</span> <span class="kr">any</span><span class="p">[]</span> <span class="p">?</span> <span class="nx">Columns</span> <span class="kd">extends</span> <span class="nb">Array</span><span class="o"><</span><span class="nx">infer</span> <span class="nx">T</span><span class="o">></span> <span class="p">?</span> <span class="nx">T</span> <span class="p">:</span> <span class="nx">never</span> <span class="p">:</span> <span class="nx">key</span><span class="p">;</span> <span class="nl">value</span><span class="p">:</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="dl">"</span><span class="s2">numberArray</span><span class="dl">"</span> <span class="p">?</span> <span class="p">[</span> <span class="nx">TypeOfPath</span><span class="o"><</span><span class="nx">Exclude</span><span class="o"><</span><span class="nx">TableSchema</span><span class="p">,</span> <span class="kc">undefined</span><span class="o">></span><span class="p">,</span> <span class="nx">key</span><span class="o">></span><span class="p">,</span> <span class="nx">TypeOfPath</span><span class="o"><</span><span class="nx">Exclude</span><span class="o"><</span><span class="nx">TableSchema</span><span class="p">,</span> <span class="kc">undefined</span><span class="o">></span><span class="p">,</span> <span class="nx">key</span><span class="o">></span><span class="p">,</span> <span class="p">]</span> <span class="p">:</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="dl">"</span><span class="s2">stringToString</span><span class="dl">"</span> <span class="p">?</span> <span class="kr">string</span> <span class="p">:</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="dl">"</span><span class="s2">stringToNumber</span><span class="dl">"</span> <span class="p">?</span> <span class="kr">string</span> <span class="p">:</span> <span class="nx">Type</span> <span class="kd">extends</span> <span class="dl">"</span><span class="s2">array</span><span class="dl">"</span> <span class="p">?</span> <span class="nb">Array</span><span class="o"><</span><span class="nx">TypeOfPath</span><span class="o"><</span><span class="nx">Exclude</span><span class="o"><</span><span class="nx">TableSchema</span><span class="p">,</span> <span class="kc">undefined</span><span class="o">></span><span class="p">,</span> <span class="nx">key</span><span class="o">>></span> <span class="p">:</span> <span class="nx">TypeOfPath</span><span class="o"><</span><span class="nx">Exclude</span><span class="o"><</span><span class="nx">TableSchema</span><span class="p">,</span> <span class="kc">undefined</span><span class="o">></span><span class="p">,</span> <span class="nx">key</span><span class="o">></span><span class="p">;</span> <span class="p">};</span> <span class="p">}[</span><span class="nx">Path</span><span class="p">];</span> <span class="kd">type</span> <span class="nx">Filter</span><span class="o"><</span> <span class="nx">TableSchema</span> <span class="kd">extends</span> <span class="p">{</span> <span class="p">[</span><span class="na">k</span><span class="p">:</span> <span class="kr">string</span><span class="p">]:</span> <span class="kr">any</span> <span class="p">}</span> <span class="o">|</span> <span class="kc">undefined</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">Columns</span> <span class="kd">extends</span> <span class="o">|</span> <span class="nb">Array</span><span class="o"><</span> <span class="nx">TableSchema</span> <span class="kd">extends</span> <span class="kc">undefined</span> <span class="p">?</span> <span class="kr">string</span> <span class="p">:</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">TableSchema</span><span class="o">></span> <span class="o">></span> <span class="o">|</span> <span class="kc">undefined</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">ColumnsExclude</span> <span class="kd">extends</span> <span class="o">|</span> <span class="nb">Array</span><span class="o"><</span> <span class="nx">TableSchema</span> <span class="kd">extends</span> <span class="kc">undefined</span> <span class="p">?</span> <span class="kr">string</span> <span class="p">:</span> <span class="nx">StringPathLeavesOf</span><span class="o"><</span><span class="nx">TableSchema</span><span class="o">></span> <span class="o">></span> <span class="o">|</span> <span class="kc">undefined</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">,</span> <span class="nx">D</span> <span class="kd">extends</span> <span class="kr">number</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="o">></span> <span class="o">=</span> <span class="p">[</span><span class="nx">D</span><span class="p">]</span> <span class="kd">extends</span> <span class="p">[</span><span class="nx">never</span><span class="p">]</span> <span class="p">?</span> <span class="nx">never</span> <span class="p">:</span> <span class="o">|</span> <span class="nx">FilterBy</span><span class="o"><</span> <span class="k">typeof</span> <span class="nx">FILTER_OPERATION_MAPPING_STRING_TO_STRING</span><span class="p">,</span> <span class="dl">"</span><span class="s2">stringToString</span><span class="dl">"</span><span class="p">,</span> <span class="nx">TableSchema</span><span class="p">,</span> <span class="nx">Columns</span><span class="p">,</span> <span class="nx">ColumnsExclude</span> <span class="o">></span> <span class="o">|</span> <span class="p">{</span> <span class="p">[</span><span class="nx">k</span> <span class="k">in</span> <span class="kr">keyof</span> <span class="k">typeof</span> <span class="nx">FILTER_CONDITION_MAPPING</span><span class="p">]?:</span> <span class="nx">Filter</span><span class="o"><</span> <span class="nx">TableSchema</span><span class="p">,</span> <span class="nx">Columns</span><span class="p">,</span> <span class="nx">ColumnsExclude</span><span class="p">,</span> <span class="nx">Prev</span><span class="p">[</span><span class="nx">D</span><span class="p">]</span> <span class="o">></span><span class="p">;</span> <span class="p">};</span> <span class="kd">type</span> <span class="nx">Test555</span> <span class="o">=</span> <span class="nx">Filter</span><span class="o"><</span><span class="p">{</span> <span class="na">aa</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span> <span class="nl">bb</span><span class="p">:</span> <span class="p">{</span> <span class="na">xx</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span> <span class="nl">yy</span><span class="p">:</span> <span class="kr">string</span> <span class="p">};</span> <span class="nl">cc</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="p">}</span><span class="o">></span><span class="p">;</span> |
After introducing typia
(typescript-json
at that time), many dev.to
users (maybe?) started using it and wrote lots issues for bug reportings or new feature suggestions, too. Resolving issues for six months, typia
became much stronger for TypeScript types.
For six months of improvements, typia
could support template literal types and built-in class types like Uint8Array
. Sometimes, bug from horrible types like “Array rest parametrized tuple type” or “endless recursive and conditional types” had been reported.
Anyway, I’d enhanced and resolved all of those issues, and now I say that “typia
supports every TypeScript type, with confidence. Of course, the word “every TypeScript type” could be broken in any time, but it is not now (maybe).
Comment Tags
Some users requested typia
to support much more types even TypeScript does not support.
To response to their inspirations, I’d studied solution for a while and found a good way at the right time. It is extending typia
‘s spec through comment tags. For an example, JavaScript does not support integer type, but typia
can validate the integer type through @type int
comment tag.
Below is an example using such comment tags. Although those comment tags are written as a comment, but they’re compile time safe. If wrong grammered comment tags being used, typia
will generate compilation error, therefore no need to worry about runtime error by mistakes.
1 2 3 |
<span class="k">export</span> <span class="kr">interface</span> <span class="nx">TagExample</span> <span class="p">{</span> <span class="cm">/* ----------------------------------------------------------- ARRAYS ----------------------------------------------------------- */</span> <span class="cm">/** * You can limit array length like below. * * @minItems 3 * @maxItems 10 * * Also, you can use `@items` tag instead. * * @items (5, 10] --> 5 < length <= 10 * @items [7 --> 7 <= length * @items 12) --> length < 12 * * Furthermore, you can use additional tags for each item. * * @type uint * @format uuid */</span> <span class="nl">array</span><span class="p">:</span> <span class="nb">Array</span><span class="o"><</span><span class="kr">string</span><span class="o">|</span><span class="kr">number</span><span class="o">></span><span class="p">;</span> <span class="cm">/** * If two-dimensional array comes, length limit would work for * both 1st and 2nd level arrays. Also using additional tags * for each item (string) would still work. * * @items (5, 10) * @format url */</span> <span class="nl">matrix</span><span class="p">:</span> <span class="kr">string</span><span class="p">[][];</span> <span class="cm">/* ----------------------------------------------------------- NUMBERS ----------------------------------------------------------- */</span> <span class="cm">/** * Type of number. * * It must be one of integer or unsigned integer. * * @type int * @type uint */</span> <span class="nl">type</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span> <span class="cm">/** * You can limit range of numeric value like below. * * @minimum 5 * @maximum 10 * * Also, you can use `@range` tag instead. * * @range (5, 10] --> 5 < x <= 10 * @range [7 --> 7 <= x * @range 12) --> x < 12 */</span> <span class="nl">range</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span> <span class="cm">/** * Step tag requires minimum or exclusiveMinimum tag. * * 3, 13, 23, 33, ... * * @step 10 * @exclusiveMinimum 3 * @range [3 */</span> <span class="nl">step</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span> <span class="cm">/** * Value must be multiple of the given number. * * -5, 0, 5, 10, 15, ... * * @multipleOf 5 */</span> <span class="nl">multipleOf</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span> <span class="cm">/* ----------------------------------------------------------- STRINGS ----------------------------------------------------------- */</span> <span class="cm">/** * You can limit string length like below. * * @minLength 3 * @maxLength 10 * * Also, you can use `@length` tag instead. * * @length 10 --> length = 10 * @length [3, 7] --> 3 <= length && length <= 7 * @length (5, 10) --> 5 < length && length < 10 * @length [4 --> 4 < length * @length 7) --> length < 7 */</span> <span class="nl">length</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="cm">/** * Mobile number composed by only numbers. * * Note that, `typia` does not support flag of regex, * because JSON schema definition does not support it either. * Therefore, write regex pattern without `/` characters and flag. * * @pattern ^0[0-9]{7,16} * -> RegExp(/[0-9]{7,16}/).test("01012345678") */</span> <span class="nl">mobile</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="cm">/** * E-mail address. * * @format email */</span> <span class="nl">email</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="cm">/** * UUID value. * * @format uuid */</span> <span class="nl">uuid</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="cm">/** * URL address. * * @format url */</span> <span class="nl">url</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="cm">/** * IPv4 address. * * @format ipv4 */</span> <span class="nl">ipv4</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="cm">/** * IPv6 address. * * @format ipv6 */</span> <span class="nl">ipv6</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span> <span class="p">}</span> |
Preparing Protocol Buffer
1 2 3 4 5 6 7 8 9 10 11 |
<span class="c1">// Protocol Buffer message structure, content of *.proto file</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">message</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">():</span> <span class="kr">string</span><span class="p">;</span> <span class="c1">// Binary data to JavaScript instance</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">decode</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">buffer</span><span class="p">:</span> <span class="nb">Uint8Array</span><span class="p">):</span> <span class="nx">T</span><span class="p">;</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">isDecode</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">buffer</span><span class="p">:</span> <span class="nb">Uint8Array</span><span class="p">):</span> <span class="nx">T</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">assertDecode</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">buffer</span><span class="p">:</span> <span class="nb">Uint8Array</span><span class="p">):</span> <span class="nx">T</span><span class="p">;</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">validateDecode</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">buffer</span><span class="p">:</span> <span class="nb">Uint8Array</span><span class="p">):</span> <span class="nx">IValidation</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">;</span> <span class="c1">// JavaScript instance to Binary data of Protobuf</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">encode</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">T</span><span class="p">):</span> <span class="nb">Uint8Array</span><span class="p">;</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">isEncode</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">T</span><span class="p">):</span> <span class="nb">Uint8Array</span> <span class="o">|</span> <span class="kc">null</span><span class="p">;</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">assertEncode</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">T</span><span class="p">):</span> <span class="nb">Uint8Array</span><span class="p">;</span> <span class="k">export</span> <span class="kd">function</span> <span class="nx">validateEncode</span><span class="o"><</span><span class="nx">T</span><span class="o">></span><span class="p">(</span><span class="nx">input</span><span class="p">:</span> <span class="nx">T</span><span class="p">):</span> <span class="nx">IValidation</span><span class="o"><</span><span class="nb">Uint8Array</span><span class="o">></span><span class="p">;</span> |
In nowadays, I am developing Protocol Buffer features.
ThoseT features are not published as stable version yet, but you can experience them through dev version. Also, you can read detailed manual about those Protocol Buffer features in Guide Documents – Protocol Buffer of typia
.
1 2 |
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">typia</span><span class="p">.</span><span class="nx">message</span><span class="o"><</span><span class="nx">ObjectSimple</span><span class="o">></span><span class="p">());</span> |
1234 <span class="na">syntax</span> <span class="o">=</span> <span class="s">"proto3"</span><span class="p">;</span><span class="kd">message</span> <span class="nc">ObjectSimple</span> <span class="p">{</span> <span class="kd">message</span> <span class="nc">IBox3D</span> <span class="p">{</span> <span class="n">ObjectSimple.IPoint3D</span> <span class="na">scale</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">ObjectSimple.IPoint3D</span> <span class="na">position</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">ObjectSimple.IPoint3D</span> <span class="na">rotate</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="n">ObjectSimple.IPoint3D</span> <span class="na">pivot</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span> <span class="p">}</span> <span class="kd">message</span> <span class="nc">IPoint3D</span> <span class="p">{</span> <span class="kt">double</span> <span class="na">x</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="kt">double</span> <span class="na">y</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="kt">double</span> <span class="na">z</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="p">}</span><span class="p">}</span>
Those features are suggested by my neighbor TypeScript backend developer who is suffering from Protocol Buffer development. Although there’re some libraries supporting Protocol Buffer in TypeScript, but they’re not so convenient.
Therefore, he suggested them hoping to implement Protocol Buffer features very easily like other typia
functions can be done with only one line. Listening his opinion and sympathizing with necessity, and it seems to make typia
more famous, I’ve accepted his suggestion.
Just wait a month, then you TypeScript developers can implement Protocol Buffer data very easily, than any other language. Also, let’s make typia
more famous!
Nestia – boosted up validation decorator
Nestia is a helper library set for
NestJS
, supporting below features:
@nestia/core
: 15,000x times faster validation decorator usingtypia
@nestia/sdk
: evolved SDK and Swagger generator for@nestia/core
nestia
: just CLI (command line interface) tool
Developing typia
and measuring performance benchmark with other competitive validator libraries, I’ve known that class-validator
is the slowest one and its validation speed is maximum 15,000x times slower than mine, typia
.
However, NestJS
, the most famous backend framework in TypeScript, is using the slowest class-validator
. Therefore, some TypeScript developers have identified that they’re using such slowest validator on their backend system (by my previous dev.to
article), and requested me to support new validation decorator for NestJS
.
In response to their desire, I’ve made a new library @nestia/core
. It provides 15,000x faster validation decorator than ordinary NestJS validator decorator using class-validator
.
1 2 3 4 5 |
<span class="k">import</span> <span class="p">{</span> <span class="nx">Controller</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@nestjs/common</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">TypedBody</span><span class="p">,</span> <span class="nx">TypedRoute</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@nestia/core</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">IBbsArticle</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@bbs-api/structures/IBbsArticle</span><span class="dl">"</span><span class="p">;</span> <span class="p">@</span><span class="nd">Controller</span><span class="p">(</span><span class="dl">"</span><span class="s2">bbs/articles</span><span class="dl">"</span><span class="p">)</span> <span class="k">export</span> <span class="kd">class</span> <span class="nx">BbsArticlesController</span> <span class="p">{</span> <span class="cm">/** * Store a new content. * * @param inupt Content to store * @returns Newly archived article */</span> <span class="p">@</span><span class="nd">TypedRoute</span><span class="p">.</span><span class="nx">Post</span><span class="p">()</span> <span class="c1">// 10x faster and safer JSON.stringify()</span> <span class="k">public</span> <span class="k">async</span> <span class="nx">store</span><span class="p">(</span> <span class="p">@</span><span class="nd">TypedBody</span><span class="p">()</span> <span class="nx">input</span><span class="p">:</span> <span class="nx">IBbsArticle</span><span class="p">.</span><span class="nx">IStore</span> <span class="c1">// supoer-fast validator</span> <span class="p">):</span> <span class="nb">Promise</span><span class="o"><</span><span class="nx">IBbsArticle</span><span class="o">></span><span class="p">;</span> <span class="p">}</span> |
However, as NestJS
can generate swagger documents only when using the slowest class-validator
decorator, I had to make a new program @nestia/sdk
, which can generate swagger documents from @nestia/core
decorator.
For reference, @nestia/sdk
also can generate SDK (Software Development Kit) library for client developers, by analyzing backend server codes in the compliation level. If I write next article in here dev.to
, subject of the new article would be this nestia
and SDK library.
In fact, I had developed nestia for a long time. However, previous
nestia
had focused only on SDK library generation. Beforetypia
, there had not been any consideration about developing faster validation decorator.Therefore, only
@nestia/core
is the new library made by requirements from TypeScript backend developers.@nestia/sdk
is just a little bit evolved version of previousnestia
, to support@nestia/core
.
SDK library generated by @nestia/sdk
1 2 3 4 5 6 7 8 |
<span class="k">import</span> <span class="p">{</span> <span class="nx">Fetcher</span><span class="p">,</span> <span class="nx">IConnection</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">@nestia/fetcher</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> < |