学习 Typescript 通常是一次重新发现之旅。您的最初印象可能非常具有欺骗性:这不就是一种注释 Javascript 的方式,所以编译器可以帮助我找到潜在的错误吗?
通过 r/mevlix@reddit
虽然这句话通常是正确的,但随着您继续前进,您会发现该语言最不可思议的力量在于组合、推断和操纵类型。
本文将总结几个技巧,帮助您充分发挥该语言的潜力。
#1 思考{Set}
类型对于程序员来说是一个日常概念,但要简洁地定义它却出奇地困难。我发现将Set用作概念模型会很有帮助。
例如,新学习者发现 Typescript 的组合类型的方式违反直觉。举个很简单的例子:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Measure</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Style</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">color</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-comment-color)">// typed { radius: number; color: string }</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Circle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">Measure</span> <span style="color:var(--syntax-error-color)">&</span> <span style="color:var(--syntax-name-color)">Style</span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>
如果您&
在逻辑 AND 的意义上解释运算符,您可能希望Circle
它是一个虚拟类型,因为它是两种类型的结合,没有任何重叠字段。这不是打字稿的工作方式。相反,在Set中思考更容易推断出正确的行为:
- 每种类型都是一组值。
- 有些集合是无限的:字符串、数字;一些有限的:布尔值,未定义的,......
unknown
是通用集(包括所有值),而never
是空集(包括无值)。- 类型
Measure
是所有对象的集合,包含一个名为 的数字字段radius
。与 相同Style
。 &
运算符创建一个Intersection:Measure & Style
表示包含radius
和字段的一组对象color
,这实际上是一个较小的 Set,但具有更常用的字段。- 类似地,
|
运算符创建一个Union:一个更大的 Set 但可能具有更少的常用字段(如果组合了两个对象类型)。
Set还有助于理解可赋值性:仅当值的类型是目标类型的子集时才允许赋值:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">ShapeKind</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">rect</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">foo</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">getSomeString</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">ShapeKind</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">rect</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// disallowed because string is not subset of ShapeKind</span>
<span style="color:var(--syntax-name-color)">shape</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">foo</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// allowed because ShapeKind is subset of string</span>
<span style="color:var(--syntax-name-color)">foo</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>
以下文章对 Set 中的思维方式进行了出色的详尽介绍。
#2 理解声明的类型和缩小的类型
一个极其强大的打字稿功能是基于控制流的自动类型缩小。这意味着变量在代码位置的任何特定点都有两种类型与之关联:声明类型和缩小类型。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">foo</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">x</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">typeof</span> <span style="color:var(--syntax-name-color)">x</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">string</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-comment-color)">// x's type is narrowed to string, so .length is valid</span>
<span style="color:var(--syntax-name-color)">console</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">log</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">x</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">length</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-comment-color)">// assignment respects declaration type, not narrowed type</span>
<span style="color:var(--syntax-name-color)">x</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-name-color)">console</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">log</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">x</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">length</span><span style="color:var(--syntax-text-color)">);</span> <span style="color:var(--syntax-comment-color)">// disallowed because x is now number</span>
<span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">else</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">...</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
#3 使用有区别的联合而不是可选字段
在定义一组像 Shape 这样的多态类型时,很容易从以下开始:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Shape</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">kind</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">rect</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">radius</span><span style="color:var(--syntax-text-color)">?:</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">width</span><span style="color:var(--syntax-text-color)">?:</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">height</span><span style="color:var(--syntax-text-color)">?:</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">getArea</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Shape</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">kind</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-text-color)">?</span>
<span style="color:var(--syntax-text-color)">Math</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">PI</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">radius</span><span style="color:var(--syntax-error-color)">!</span> <span style="color:var(--syntax-error-color)">**</span> <span style="color:var(--syntax-literal-color)">2</span>
<span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">width</span><span style="color:var(--syntax-error-color)">!</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">height</span><span style="color:var(--syntax-error-color)">!</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
非空断言(访问radius
、width
和字段时)是必需的,因为与其他字段height
之间没有建立关系。kind
相反,discriminated union 是一个更好的解决方案:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Circle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">kind</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Rect</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">kind</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">rect</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">width</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">height</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Shape</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">Circle</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-name-color)">Rect</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">getArea</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Shape</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">kind</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-text-color)">?</span>
<span style="color:var(--syntax-text-color)">Math</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">PI</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">radius</span> <span style="color:var(--syntax-error-color)">**</span> <span style="color:var(--syntax-literal-color)">2</span>
<span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">width</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">height</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
类型缩小消除了强制转换的需要。
#4 使用类型谓词来避免类型断言
如果你以正确的方式使用打字稿,你应该很少会发现自己使用显式类型断言(比如value as SomeType
);但是,有时您仍然会感到冲动,例如:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Circle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">kind</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Rect</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">kind</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">rect</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">width</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">height</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Shape</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">Circle</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-name-color)">Rect</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">isCircle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Shape</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">kind</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">isRect</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Shape</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">kind</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">rect</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">myShapes</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Shape</span><span style="color:var(--syntax-text-color)">[]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">getShapes</span><span style="color:var(--syntax-text-color)">();</span>
<span style="color:var(--syntax-comment-color)">// error because typescript doesn't know the filtering</span>
<span style="color:var(--syntax-comment-color)">// narrows typing</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">circles</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Circle</span><span style="color:var(--syntax-text-color)">[]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">myShapes</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">filter</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">isCircle</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-comment-color)">// you may be inclined to add an assertion:</span>
<span style="color:var(--syntax-comment-color)">// const circles = myShapes.filter(isCircle) as Circle[];</span>
</code></span></span>
一个更优雅的解决方案是改为更改isCircle
并isRect
返回类型谓词,这样它们可以帮助 Typescript 在调用后进一步缩小类型范围filter
:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">isCircle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Shape</span><span style="color:var(--syntax-text-color)">):</span> <span style="color:var(--syntax-name-color)">shape</span> <span style="color:var(--syntax-declaration-color)">is</span> <span style="color:var(--syntax-name-color)">Circle</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">kind</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">isRect</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Shape</span><span style="color:var(--syntax-text-color)">):</span> <span style="color:var(--syntax-name-color)">shape</span> <span style="color:var(--syntax-declaration-color)">is</span> <span style="color:var(--syntax-name-color)">Rect</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">kind</span> <span style="color:var(--syntax-error-color)">===</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">rect</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">...</span>
<span style="color:var(--syntax-comment-color)">// now you get Circle[] type inferred correctly</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">circles</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">myShapes</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">filter</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">isCircle</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>
#5 控制联合类型的分布方式
类型推断是 Typescript 的本能;大多数时候,它会默默地为你工作。但是,您可能需要对含糊不清的细微情况进行干预。分布式条件类型就是其中一种情况。
假设我们有一个ToArray
辅助类型,如果输入类型还不是一个,它会返回一个数组类型:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">ToArray</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">T</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">T</span> <span style="color:var(--syntax-declaration-color)">extends</span> <span style="color:var(--syntax-text-color)">Array</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">unknown</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-text-color)">?</span> <span style="color:var(--syntax-name-color)">T</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">T</span><span style="color:var(--syntax-text-color)">[];</span>
</code></span></span>
对于以下类型,您认为应该推断出什么?
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Foo</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">ToArray</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-error-color)">|</span><span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>
答案是string[] | number[]
。但这是模棱两可的。为什么不(string | number)[]
呢?
默认情况下,当 typescript 遇到string | number
泛型参数(T
此处)的联合类型(此处)时,它会分配到每个成分中,这就是您得到string[] | number[]
. 这种行为可以通过使用特殊语法并包装T
在一对 中来改变[]
,例如:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">ToArray</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">T</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">T</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-declaration-color)">extends</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-text-color)">Array</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">unknown</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-text-color)">?</span> <span style="color:var(--syntax-name-color)">T</span> <span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">T</span><span style="color:var(--syntax-text-color)">[];</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Foo</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">ToArray</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>
NowFoo
被推断为 type (string | number)[]
。
#6 在编译时使用详尽检查来捕获未处理的情况
当对枚举进行 switch-casing 时,一个好习惯是主动为不期望的情况犯错,而不是像在其他编程语言中那样默默地忽略它们:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">getArea</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Shape</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">switch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">kind</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">case</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">Math</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">PI</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">radius</span> <span style="color:var(--syntax-error-color)">**</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">case</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">rect</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">width</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">height</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">default</span><span style="color:var(--syntax-text-color)">:</span>
<span style="color:var(--syntax-declaration-color)">throw</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-text-color)">Error</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">Unknown shape kind</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
使用 Typescript,您可以让静态类型检查通过使用以下never
类型更早地为您找到错误:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">getArea</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Shape</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">switch</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">kind</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">case</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">Math</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">PI</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">radius</span> <span style="color:var(--syntax-error-color)">**</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">case</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">rect</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">:</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">width</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">height</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">default</span><span style="color:var(--syntax-text-color)">:</span>
<span style="color:var(--syntax-comment-color)">// you'll get a type-checking error below </span>
<span style="color:var(--syntax-comment-color)">// if any shape.kind is not handled above</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">_exhaustiveCheck</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">never</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">throw</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-text-color)">Error</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">Unknown shape kind</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">);</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>
有了这个,就不可能getArea
在添加新的形状种类时忘记更新函数。
该技术背后的基本原理是该never
类型不能分配任何东西,除了never
. shape.kind
如果case 语句穷尽了所有候选者,则唯一可能到达的类型default
是 never;但是,如果任何候选人未被涵盖,它将泄漏到default
分支并导致无效分配。
type
#7更 喜欢interface
在打字稿中,当用于键入对象时type
,它们是非常相似的结构。尽管可能存在争议,但我的建议是在大多数情况下interface
始终使用,并且仅在满足以下任一条件时才使用:type
interface
-
您想要利用 的“合并”功能
interface
。 -
您有涉及类/接口层次结构的 OO 样式代码。
否则,始终使用更通用的type
构造会产生更一致的代码。
#8 在适当的时候优先使用元组而不是数组
对象类型是输入结构化数据的常用方式,但有时您可能需要更简洁的表示方式,而是使用简单的数组。例如,我们Circle
可以这样定义:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Circle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">)[];</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">circle</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Circle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">1.0</span><span style="color:var(--syntax-text-color)">];</span> <span style="color:var(--syntax-comment-color)">// [kind, radius]</span>
</code></span></span>
但是这种输入不必要地松散,您可以通过创建类似['circle', '1.0']
. 我们可以通过使用 Tuple 来使其更严格:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Circle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">];</span>
<span style="color:var(--syntax-comment-color)">// you'll get an error below</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">circle</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">Circle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">1.0</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">];</span>
</code></span></span>
元组用法的一个很好的例子是 React 的useState
.
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">setName</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">useState</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">''</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>
它既紧凑又类型安全。
#9 控制推断类型的一般性或具体性
Typescript 在进行类型推断时使用合理的默认行为,旨在简化常见情况下的代码编写(因此类型不需要显式注释)。有几种方法可以调整它的行为。
- 用于
const
缩小到最具体的类型
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">foo</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">foo</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-text-color)">};</span> <span style="color:var(--syntax-comment-color)">// typed: { name: string }</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">Bar</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">bar</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-declaration-color)">const</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// typed: { name: 'bar' }</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">a</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">];</span> <span style="color:var(--syntax-comment-color)">// typed: number[]</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">b</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-declaration-color)">const</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// typed: [1, 2]</span>
<span style="color:var(--syntax-comment-color)">// typed { kind: 'circle; radius: number }</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">circle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">kind</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-declaration-color)">const</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">1.0</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-comment-color)">// the following won't work if circle wasn't initialized</span>
<span style="color:var(--syntax-comment-color)">// with the const keyword</span>
<span style="color:var(--syntax-declaration-color)">let</span> <span style="color:var(--syntax-name-color)">shape</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">kind</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">rect</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">circle</span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>
- 用于
satisfies
检查类型而不影响推断类型
考虑以下示例:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">NamedCircle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">?:</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">circle</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">NamedCircle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">1.0</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">yeah</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-comment-color)">// error because circle.name can be undefined</span>
<span style="color:var(--syntax-name-color)">console</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">log</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">circle</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">length</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>
我们得到一个错误,因为根据circle
的声明类型NamedCircle
,name
字段确实可以是未定义的,即使变量初始值设定项提供了一个字符串值。当然,我们可以删除类型注释,但我们将放弃对对象: NamedCircle
有效性的类型检查。circle
相当进退两难。
幸运的是,Typescript 4.9 引入了一个新satisfies
关键字,它允许您在不改变推断类型的情况下检查类型:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">NamedCircle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">name</span><span style="color:var(--syntax-text-color)">?:</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-comment-color)">// error because radius violates NamedCircle</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">wrongCircle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">1.0</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">ha</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">satisfies</span> <span style="color:var(--syntax-name-color)">NamedCircle</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">circle</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">1.0</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">yeah</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">satisfies</span> <span style="color:var(--syntax-name-color)">NamedCircle</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// circle.name can't be undefined now</span>
<span style="color:var(--syntax-name-color)">console</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">log</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">circle</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">name</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">length</span><span style="color:var(--syntax-text-color)">);</span>
</code></span></span>
修改后的版本享有两个好处:保证对象文字符合NamedCircle
类型,并且推断类型具有不可为空的name
字段。
#10infer
用于创建额外的泛型类型参数
在设计实用函数和类型时,您经常会觉得需要使用从给定类型参数中提取的类型。在这种情况下,infer
关键字就派上用场了。它可以帮助您即时推断出新的类型参数。这里有两个简单的例子:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// gets the unwrapped type out of a Promise;</span>
<span style="color:var(--syntax-comment-color)">// idempotent if T is not Promise</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">ResolvedPromise</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">T</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">T</span> <span style="color:var(--syntax-declaration-color)">extends</span> <span style="color:var(--syntax-text-color)">Promise</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">infer</span> <span style="color:var(--syntax-name-color)">U</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-text-color)">?</span> <span style="color:var(--syntax-name-color)">U</span> <span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">T</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">t</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">ResolvedPromise</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-text-color)">Promise</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-error-color)">>></span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// t: string</span>
<span style="color:var(--syntax-comment-color)">// gets the flattened type of array T;</span>
<span style="color:var(--syntax-comment-color)">// idempotent if T is not array</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Flatten</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">T</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">T</span> <span style="color:var(--syntax-declaration-color)">extends</span> <span style="color:var(--syntax-text-color)">Array</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">infer</span> <span style="color:var(--syntax-name-color)">E</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-text-color)">?</span> <span style="color:var(--syntax-name-color)">Flatten</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">E</span><span style="color:var(--syntax-error-color)">></span> <span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">T</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">e</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">Flatten</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">[][]</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-comment-color)">// e: number</span>
</code></span></span>
infer
关键字的工作原理可以T extends Promise<infer U>
理解为:假设 T 与某些实例化的通用 Promise 类型兼容,即兴创作一个类型参数 U 使其工作。因此,如果T
被实例化为Promise<string>
,则 的解U
将是string
。
#11通过在类型操作上发挥创意来 保持DRY
Typescript 提供了强大的类型操作语法和一组非常有用的实用程序,可帮助您将代码重复减少到最低限度。这里只是一些特别的例子:
- 而不是复制字段声明:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">User</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">age</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">gender</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">country</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">city</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Demographic</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">age</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">number</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">gender</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Geo</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">country</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">city</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">};</span>
</code></span></span>
,使用Pick
实用程序提取新类型:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">User</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">age</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">gender</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">country</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">city</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">string</span>
<span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Demographic</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Pick</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">User</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">age</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-error-color)">|</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">gender</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Geo</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Pick</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">User</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">country</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-error-color)">|</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">city</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">;</span>
</code></span></span>
- 而不是复制函数的返回类型
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">createCircle</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">kind</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-declaration-color)">const</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-name-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">1.0</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">transformCircle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">circle</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-text-color)">kind</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">number</span> <span style="color:var(--syntax-text-color)">})</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">...</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">transformCircle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">createCircle</span><span style="color:var(--syntax-text-color)">());</span>
</code></span></span>
,用于ReturnType<T>
提取它:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">createCircle</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">kind</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">circle</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-declaration-color)">const</span><span style="color:var(--syntax-text-color)">,</span>
<span style="color:var(--syntax-name-color)">radius</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">1.0</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-declaration-color)">function</span> <span style="color:var(--syntax-name-color)">transformCircle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">circle</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">ReturnType</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-declaration-color)">typeof</span> <span style="color:var(--syntax-name-color)">createCircle</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">...</span>
<span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">transformCircle</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">createCircle</span><span style="color:var(--syntax-text-color)">());</span>
</code></span></span>
- 而不是并行同步两种类型的形状(此处为 typeof config 和 Factory):
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">ContentTypes</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">news</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">blog</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">video</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// config for indicating what content types are enabled</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">config</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">news</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">blog</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">video</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">false</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">satisfies</span> <span style="color:var(--syntax-text-color)">Record</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">ContentTypes</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">boolean</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// factory for creating contents</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Factory</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-name-color)">createNews</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">Content</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">createBlog</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">Content</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>
,使用Mapped Type和Template Literal Type根据配置的形状自动推断出正确的工厂类型:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">ContentTypes</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">news</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">blog</span><span style="color:var(--syntax-string-color)">'</span> <span style="color:var(--syntax-error-color)">|</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">video</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// generic factory type with a inferred list of methods</span>
<span style="color:var(--syntax-comment-color)">// based on the shape of the given Config</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">ContentFactory</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">Config</span> <span style="color:var(--syntax-declaration-color)">extends</span> <span style="color:var(--syntax-text-color)">Record</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">ContentTypes</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">boolean</span><span style="color:var(--syntax-error-color)">>></span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span>
<span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">k</span> <span style="color:var(--syntax-declaration-color)">in</span> <span style="color:var(--syntax-declaration-color)">string</span> <span style="color:var(--syntax-error-color)">&</span> <span style="color:var(--syntax-declaration-color)">keyof</span> <span style="color:var(--syntax-name-color)">Config</span> <span style="color:var(--syntax-declaration-color)">as</span> <span style="color:var(--syntax-name-color)">Config</span><span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-name-color)">k</span><span style="color:var(--syntax-text-color)">]</span> <span style="color:var(--syntax-declaration-color)">extends</span> <span style="color:var(--syntax-declaration-color)">true</span>
<span style="color:var(--syntax-text-color)">?</span> <span style="color:var(--syntax-string-color)">`create</span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">Capitalize</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">k</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)">`</span>
<span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">never</span><span style="color:var(--syntax-text-color)">]:</span> <span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-name-color)">Content</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-text-color)">};</span>
<span style="color:var(--syntax-comment-color)">// config for indicating what content types are enabled</span>
<span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">config</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">news</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">blog</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">video</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">false</span> <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-name-color)">satisfies</span> <span style="color:var(--syntax-text-color)">Record</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-name-color)">ContentTypes</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-name-color)">boolean</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">type</span> <span style="color:var(--syntax-name-color)">Factory</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">ContentFactory</span><span style="color:var(--syntax-error-color)"><</span><span style="color:var(--syntax-declaration-color)">typeof</span> <span style="color:var(--syntax-name-color)">config</span><span style="color:var(--syntax-error-color)">></span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-comment-color)">// Factory: {</span>
<span style="color:var(--syntax-comment-color)">// createNews: () => Content;</span>
<span style="color:var(--syntax-comment-color)">// createBlog: () => Content; </span>
<span style="color:var(--syntax-comment-color)">// }</span>
</code></span></span>
发挥您的想象力,您会发现无限的探索潜力。
包起来
这篇文章涵盖了 Typescript 语言中的一组相对高级的主题。实际上,您可能会发现直接应用它们并不常见;然而,此类技术被专门为 Typescript 设计的库大量使用:如Prisma和tRPC。了解这些技巧可以帮助您更好地了解这些工具如何在幕后发挥其魔力。
PS 我们正在构建ZenStack — 一个用于使用 Next.js + Typescript 构建安全 CRUD 应用程序的工具包。我们的目标是让您节省编写样板代码的时间,并专注于构建重要的东西——用户体验。