(window.webpackJsonp=window.webpackJsonp||[]).push([[139],{864:function(t,s,a){"use strict";a.r(s);var n=a(20),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h1",{attrs:{id:"typescript-4-4"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#typescript-4-4"}},[t._v("#")]),t._v(" TypeScript 4.4")]),t._v(" "),a("h2",{attrs:{id:"针对条件表达式和判别式的别名引用进行控制流分析"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#针对条件表达式和判别式的别名引用进行控制流分析"}},[t._v("#")]),t._v(" 针对条件表达式和判别式的别名引用进行控制流分析")]),t._v(" "),a("p",[t._v("在 JavaScript 中，总会用多种方式对某个值进行检查，然后根据不同类型的值执行不同的操作。\nTypeScript 能够理解这些检查，并将它们称作为"),a("em",[t._v("类型守卫")]),t._v("。\n我们不需要在变量的每一个使用位置上都指明类型，TypeScript 的类型检查器能够利用"),a("em",[t._v("基于控制流的分析")]),t._v("技术来检查是否在前面使用了类型守卫。")]),t._v(" "),a("p",[t._v("例如，可以这样写")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("foo")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("arg"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("unknown")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("typeof")]),t._v(" arg "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("===")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'string'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("console")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("log")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("arg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUpperCase")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//           ^?")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("这个例子中，我们检查  "),a("code",[t._v("arg")]),t._v("  是否为  "),a("code",[t._v("string")]),t._v("  类型。\nTypeScript 识别出了  "),a("code",[t._v('typeof arg === "string"')]),t._v("  检查，它被当作是一个类型守卫，并且知道在  "),a("code",[t._v("if")]),t._v("  分支内  "),a("code",[t._v("arg")]),t._v("  的类型为  "),a("code",[t._v("string")]),t._v(" 。\n这样就可以正常地访问  "),a("code",[t._v("string")]),t._v("  类型上的方法，例如  "),a("code",[t._v("toUpperCase()")]),t._v(" 。")]),t._v(" "),a("p",[t._v("但如果我们将条件表达式提取到一个名为  "),a("code",[t._v("argIsString")]),t._v("  的常量会发生什么？")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 在 TS 4.3 及以下版本")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("foo")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("arg"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("unknown")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" argIsString "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("typeof")]),t._v(" arg "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("===")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'string'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("argIsString"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("console")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("log")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("arg"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUpperCase")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//              ~~~~~~~~~~~")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 错误！'unknown' 类型上不存在 'toUpperCase' 属性。")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("在之前版本的 TypeScript 中，这样做会产生错误 - 就算  "),a("code",[t._v("argIsString")]),t._v("  的值为类型守卫，TypeScript 也会丢掉这个信息。\n这不是想要的结果，因为我们可能想要在不同的地方重用这个检查。\n为了绕过这个问题，通常需要重复多次代码或使用类型断言。")]),t._v(" "),a("p",[t._v("在 TypeScript 4.4 中，情况有所改变。\n上面的例子不再产生错误！\n当 TypeScript 看到我们在检查一个常量时，会额外检查它是否包含类型守卫。\n如果那个类型守卫操作的是  "),a("code",[t._v("const")]),t._v("  常量，某个  "),a("code",[t._v("readonly")]),t._v("  属性或某个未修改的参数，那么 TypeScript 能够对该值进行类型细化。")]),t._v(" "),a("p",[t._v("不同种类的类型守卫都支持，不只是  "),a("code",[t._v("typeof")]),t._v("  类型守卫。\n例如，对于可辨识联合类型同样适用。")]),t._v(" "),a("div",{staticClass:"language-ts twoslash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Shape")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" kind"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'circle'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" radius"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" kind"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'square'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" sideLength"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("area")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("shape"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Shape"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" isCircle "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" shape"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("kind "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("===")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'circle'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("isCircle"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 知道此处为 circle")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" Math"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("PI")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" shape"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("radius "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("**")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 知道此处为 square")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" shape"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("sideLength "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("**")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("在 TypeScript 4.4 版本中对判别式的分析又进了一层 - 现在可以提取出判别式然后细化原来的对象类型。")]),t._v(" "),a("div",{staticClass:"language-ts twoslash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Shape")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" kind"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'circle'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" radius"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" kind"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'square'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" sideLength"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("area")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("shape"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Shape"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Extract out the 'kind' field first.")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" kind "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" shape"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("kind "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("===")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'circle'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We know we have a circle here!")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" Math"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("PI")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("*")]),t._v(" shape"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("radius "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("**")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We know we're left with a square here!")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" shape"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("sideLength "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("**")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("另一个例子，该函数会检查它的两个参数是否有内容。")]),t._v(" "),a("div",{staticClass:"language-ts twoslash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("doSomeChecks")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n  inputA"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("undefined")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n  inputB"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("undefined")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n  shouldDoExtraWork"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("boolean")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" mustDoWork "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" inputA "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" inputB "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("&&")]),t._v(" shouldDoExtraWork"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("mustDoWork"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// We can access 'string' properties on both 'inputA' and 'inputB'!")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" upperA "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" inputA"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUpperCase")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" upperB "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" inputB"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toUpperCase")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("TypeScript 知道如果  "),a("code",[t._v("mustDoWork")]),t._v("  为  "),a("code",[t._v("true")]),t._v("  那么  "),a("code",[t._v("inputA")]),t._v("  和  "),a("code",[t._v("inputB")]),t._v("  都存在。\n也就是说不需要编写像  "),a("code",[t._v("inputA!")]),t._v("  这样的非空断言的代码来告诉 TypeScript  "),a("code",[t._v("inputA")]),t._v("  不为  "),a("code",[t._v("undefined")]),t._v(" 。")]),t._v(" "),a("p",[t._v("一个好的性质是该分析同时具有可传递性。\nTypeScript 可以通过这些常量来理解在它们背后执行的检查。")]),t._v(" "),a("div",{staticClass:"language-ts twoslash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("f")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("x"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("boolean")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" isString "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("typeof")]),t._v(" x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("===")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'string'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" isNumber "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("typeof")]),t._v(" x "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("===")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'number'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" isStringOrNumber "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" isString "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" isNumber"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("isStringOrNumber"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//  ^?")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("else")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    x"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//  ^?")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("注意这里会有一个截点 - TypeScript 并不是毫无限制地去追溯检查这些条件表达式，但对于大多数使用场景而言已经足够了。")]),t._v(" "),a("p",[t._v("这个功能能让很多直观的 JavaScript 代码在 TypeScript 里也好用，而不会妨碍我们。\n更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/44730",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("！")]),t._v(" "),a("h2",{attrs:{id:"symbol-以及模版字符串索引签名"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#symbol-以及模版字符串索引签名"}},[t._v("#")]),t._v(" Symbol 以及模版字符串索引签名")]),t._v(" "),a("p",[t._v("TypeScript 支持使用"),a("em",[t._v("索引签名")]),t._v("来为对象的每个属性定义类型。\n这样我们就可以将对象当作字典类型来使用，把字符串放在方括号里来进行索引。")]),t._v(" "),a("p",[t._v("例如，可以编写由  "),a("code",[t._v("string")]),t._v("  类型的键映射到  "),a("code",[t._v("boolean")]),t._v("  值的类型。\n如果我们给它赋予  "),a("code",[t._v("boolean")]),t._v("  类型以外的值会报错。")]),t._v(" "),a("div",{staticClass:"language-ts twoslash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("BooleanDictionary")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("key"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("boolean")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("declare")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" myDict"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" BooleanDictionary"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 允许赋予 boolean 类型的值")]),t._v("\nmyDict"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'foo'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\nmyDict"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'bar'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 错误")]),t._v("\nmyDict"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'baz'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'oops'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("虽说在这里 "),a("a",{attrs:{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("Map")]),t._v("  可能是更适合的数据结构"),a("OutboundLink")],1),t._v("（具体的说是  "),a("code",[t._v("Map<string, boolean>")]),t._v(" ），但 JavaScript 对象通常更方便或者正是我们要操作的目标。")]),t._v(" "),a("p",[t._v("相似地， "),a("code",[t._v("Array<T>")]),t._v("  已经定义了  "),a("code",[t._v("number")]),t._v("  索引签名，我们可以插入和获取  "),a("code",[t._v("T")]),t._v("  类型的值。")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 这是 TypeScript 内置的部分 Array 类型")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Array")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("T")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("index"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token constant"}},[t._v("T")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ...")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" arr "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("Array")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(">")])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 没问题")]),t._v("\narr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'hello!'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 错误，期待一个 'string' 值")]),t._v("\narr"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("123")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("索引签名是一种非常有用的表达方式。\n然而，直到现在它们只能使用  "),a("code",[t._v("string")]),t._v("  和  "),a("code",[t._v("number")]),t._v("  类型的键（ "),a("code",[t._v("string")]),t._v("  索引签名存在一个有意为之的怪异行为，它们可以接受  "),a("code",[t._v("number")]),t._v("  类型的键，因为  "),a("code",[t._v("number")]),t._v("  会被转换为字符串）。\n这意味着 TypeScript 不允许使用  "),a("code",[t._v("symbol")]),t._v("  类型的键来索引对象。\nTypeScript 也无法表示由一部分  "),a("code",[t._v("string")]),t._v("  类型的键组成的索引签名 - 例如，对象属性名是以  "),a("code",[t._v("data-")]),t._v("  字符串开头的索引签名。")]),t._v(" "),a("p",[t._v("TypeScript 4.4 解决了这个问题，允许  "),a("code",[t._v("symbol")]),t._v("  索引签名以及模版字符串。")]),t._v(" "),a("p",[t._v("例如，TypeScript 允许声明一个接受任意  "),a("code",[t._v("symbol")]),t._v("  值作为键的对象类型。")]),t._v(" "),a("div",{staticClass:"language-ts twoslash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Colors")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("sym"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("symbol")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" red "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Symbol")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'red'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" green "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Symbol")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'green'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" blue "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("Symbol")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'blue'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" colors"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Colors "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 没问题")]),t._v("\ncolors"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("red"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("255")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" redVal "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" colors"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("red"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//  ^ number")]),t._v("\n\ncolors"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("blue"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'da ba dee'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 错误：'string' 不能赋值给 'number'")]),t._v("\n")])])]),a("p",[t._v("相似地，可以定义带有模版字符串的索引签名。\n一个场景是用来免除对以  "),a("code",[t._v("data-")]),t._v("  开头的属性名执行的 TypeScript 额外属性检查。\n当传递一个对象字面量给目标类型时，TypeScript 会检查是否存在相比于目标类型的额外属性。")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Options")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  width"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  height"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" a"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Options "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  width"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("100")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n  height"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("100")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n  "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'data-blah'")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("OptionsWithDataProps")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Options")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 允许以 'data-' 开头的属性")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("optName"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token template-string"}},[a("span",{pre:!0,attrs:{class:"token template-punctuation string"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("data-")]),a("span",{pre:!0,attrs:{class:"token interpolation"}},[a("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v("${")]),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),a("span",{pre:!0,attrs:{class:"token interpolation-punctuation punctuation"}},[t._v("}")])]),a("span",{pre:!0,attrs:{class:"token template-punctuation string"}},[t._v("`")])]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("unknown")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("let")]),t._v(" b"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" OptionsWithDataProps "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  width"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("100")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n  height"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("100")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'data-blah'")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 使用未知属性会报错，不包括以 'data-' 开始的属性")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'unknown-property'")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("最后，索引签名现在支持联合类型，只要它们是无限域原始类型的联合 - 尤其是：")]),t._v(" "),a("ul",[a("li",[a("code",[t._v("string")])]),t._v(" "),a("li",[a("code",[t._v("number")])]),t._v(" "),a("li",[a("code",[t._v("symbol")])]),t._v(" "),a("li",[t._v("模版字符串（例如  "),a("code",[t._v("`hello-${string}`")]),t._v(" ）")])]),t._v(" "),a("p",[t._v("带有以上类型的联合的索引签名会展开为不同的索引签名。")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Data")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("optName"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("symbol")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("any")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 等同于")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Data")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("optName"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("any")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("optName"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("symbol")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("any")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/44512",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h2",{attrs:{id:"defaulting-to-the-unknown-type-in-catch-variables-useunknownincatchvariables"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#defaulting-to-the-unknown-type-in-catch-variables-useunknownincatchvariables"}},[t._v("#")]),t._v(" Defaulting to the  "),a("code",[t._v("unknown")]),t._v("  Type in Catch Variables ( "),a("code",[t._v("--useUnknownInCatchVariables")]),t._v(" )")]),t._v(" "),a("h2",{attrs:{id:"异常捕获变量的类型默认为-unknown-useunknownincatchvariables"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#异常捕获变量的类型默认为-unknown-useunknownincatchvariables"}},[t._v("#")]),t._v(" 异常捕获变量的类型默认为  "),a("code",[t._v("unknown")]),t._v("  （ "),a("code",[t._v("--useUnknownInCatchVariables")]),t._v(" ）")]),t._v(" "),a("p",[t._v("在 JavaScript 中，允许使用  "),a("code",[t._v("throw")]),t._v("  语句抛出任意类型的值，并在  "),a("code",[t._v("catch")]),t._v("  语句中捕获它。\n因此，TypeScript 从前会将异常捕获变量的类型设置为  "),a("code",[t._v("any")]),t._v("  类型，并且不允许指定其它的类型注解:")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 谁知道它会抛出什么东西")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("executeSomeThirdPartyCode")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// err: any")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("console")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("error")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("message"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 可以，因为类型为 'any'")]),t._v("\n  err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("thisWillProbablyFail")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 可以，因为类型为 'any' :(")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("当 TypeScript 引入了  "),a("code",[t._v("unknown")]),t._v("  类型后，对于追求高度准确性和类型安全的用户来讲在  "),a("code",[t._v("catch")]),t._v("  语句的捕获变量处使用  "),a("code",[t._v("unknown")]),t._v("  成为了比  "),a("code",[t._v("any")]),t._v("  类型更好的选择，因为它强制我们去检测要使用的值。\n后来，TypeScript 4.0 允许用户在  "),a("code",[t._v("catch")]),t._v("  语句中明确地指定  "),a("code",[t._v("unknown")]),t._v(" （或  "),a("code",[t._v("any")]),t._v(" ）类型，这样就可以根据情况有选择一使用更严格的类型检查；\n然而，在每一处  "),a("code",[t._v("catch")]),t._v("  语句里手动指定  "),a("code",[t._v(": unknown")]),t._v("  是一件繁琐的事情。")]),t._v(" "),a("p",[t._v("因此，TypeScript 4.4 引入了一个新的标记  "),a("code",[t._v("--useUnknownInCatchVariables")]),t._v(" 。\n它将  "),a("code",[t._v("catch")]),t._v("  语句捕获变量的默认类型由  "),a("code",[t._v("any")]),t._v("  改为  "),a("code",[t._v("unknown")]),t._v(" 。")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("declare")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("executeSomeThirdPartyCode")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("executeSomeThirdPartyCode")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// err: unknown")]),t._v("\n\n  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Error! Property 'message' does not exist on type 'unknown'.")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("console")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("error")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("message"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Works! We can narrow 'err' from 'unknown' to 'Error'.")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("instanceof")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Error")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("console")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("error")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("message"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("这个标记属性于  "),a("code",[t._v("--strict")]),t._v("  标记家族的一员。\n也就是说如果你启用了  "),a("code",[t._v("--strict")]),t._v(" ，那么该标记也自动启用了。\n在 TypeScript 4.4 中，你可能会看到如下的错误：")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[t._v("Property "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'message'")]),t._v(" does not exist on "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'unknown'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nProperty "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'name'")]),t._v(" does not exist on "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'unknown'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\nProperty "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'stack'")]),t._v(" does not exist on "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("type")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'unknown'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("\n")])])]),a("p",[t._v("如果我们不想处理  "),a("code",[t._v("catch")]),t._v("  语句中  "),a("code",[t._v("unknown")]),t._v("  类型的捕获变量，那么可以明确使用  "),a("code",[t._v(": any")]),t._v("  类型注解，这样就会关闭严格类型检查。")]),t._v(" "),a("div",{staticClass:"language-ts twoslash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("declare")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("executeSomeThirdPartyCode")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("executeSomeThirdPartyCode")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("any")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("console")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("error")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("err"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("message"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Works again!")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/41013",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h2",{attrs:{id:"确切的可选属性类型-exactoptionalpropertytypes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#确切的可选属性类型-exactoptionalpropertytypes"}},[t._v("#")]),t._v(" 确切的可选属性类型 ( "),a("code",[t._v("--exactOptionalPropertyTypes")]),t._v(" )")]),t._v(" "),a("p",[t._v("在 JavaScript 中，读取对象上某个不存在的属性会得到  "),a("code",[t._v("undefined")]),t._v("  值。\n与此同时，某个已有属性的值也允许为  "),a("code",[t._v("undefined")]),t._v("  值。\n有许多 JavaScript 代码都会对这些情况一视同仁，因此最初 TypeScript 将可选属性视为添加了  "),a("code",[t._v("undefined")]),t._v("  类型。\n例如，")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Person")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  age"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("等同于：")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Person")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  age"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("|")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("undefined")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("这意味着用户可以给  "),a("code",[t._v("age")]),t._v("  明确地指定  "),a("code",[t._v("undefined")]),t._v("  值。")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" p"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Person "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Daniel'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n  age"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("undefined")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// This is okay by default.")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("因此默认情况下，TypeScript 不区分带有  "),a("code",[t._v("undefined")]),t._v("  类型的属性和不存在的属性。\n虽说这在大部分情况下是没问题的，但并非所有的 JavaScript 代码都如此。\n像是  "),a("code",[t._v("Object.assign")]),t._v(" ， "),a("code",[t._v("Object.keys")]),t._v(" ，对象展开（ "),a("code",[t._v("{ ...obj }")]),t._v(" ）和  "),a("code",[t._v("for")]),t._v(" - "),a("code",[t._v("in")]),t._v("  循环这样的函数和运算符会区别对待属性是否存在于对象之上。\n在  "),a("code",[t._v("Person")]),t._v("  例子中，如果  "),a("code",[t._v("age")]),t._v("  属性的存在与否是至关重要的，那么就可能会导致运行时错误。")]),t._v(" "),a("p",[t._v("在 TypeScript 4.4 中，新的  "),a("code",[t._v("--exactOptionalPropertyTypes")]),t._v("  标记指明了可选属性的确切表示方式，即不自动添加  "),a("code",[t._v("| undefined")]),t._v("  类型：")]),t._v(" "),a("div",{staticClass:"language-ts twoslash extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("interface")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Person")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("string")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  age"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("number")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 启用 'exactOptionalPropertyTypes'")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" p"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" Person "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  name"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'Daniel'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n  age"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("undefined")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 错误！undefined 不是一个成员")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("p",[t._v("该标记"),a("strong",[t._v("不是")]),t._v(" "),a("code",[t._v("--strict")]),t._v("  标记家族的一员，需要显式地开启。\n该标记要求同时启用  "),a("code",[t._v("--strictNullChecks")]),t._v("  标记。\n我们已经更新了 DefinitelyTyped 以及其它的声明定义来帮助进行平稳地过渡，但你仍可能遇到一些问题，这取决于代码的结构。")]),t._v(" "),a("p",[t._v("更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/43947",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h2",{attrs:{id:"类中的-static-语句块"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#类中的-static-语句块"}},[t._v("#")]),t._v(" 类中的  "),a("code",[t._v("static")]),t._v("  语句块")]),t._v(" "),a("p",[t._v("TypeScript 4.4 支持了 "),a("a",{attrs:{href:"https://github.com/tc39/proposal-class-static-block#ecmascript-class-static-initialization-blocks",target:"_blank",rel:"noopener noreferrer"}},[t._v("类中的  "),a("code",[t._v("static")]),t._v("  语句块"),a("OutboundLink")],1),t._v("，一个即将到来的 ECMAScript 特性，它能够帮助编写复杂的静态成员初始化代码。")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("declare")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("someCondition")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("boolean")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Foo")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" count "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n  "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 静态语句块：")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("someCondition")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n      Foo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("count"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("在静态语句块中允许编写一系列语句，它们可以访问类中的私有字段。\n也就是说在初始化代码中能够编写语句，不会暴露变量，并且可以完全访问类的内部信息。")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("declare")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("loadLastInstances")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("any")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Foo")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" #count "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("get")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("count")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" Foo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("#count"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n      "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" lastInstances "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("loadLastInstances")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n      Foo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("#count "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+=")]),t._v(" lastInstances"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("length"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("若不使用  "),a("code",[t._v("static")]),t._v("  语句块也能够编写上述代码，只不过需要使用一些折中的 hack 手段。")]),t._v(" "),a("p",[t._v("一个类可以有多个  "),a("code",[t._v("static")]),t._v("  语句块，它们的运行顺序与编写顺序一致。")]),t._v(" "),a("div",{staticClass:"language-ts extra-class"},[a("pre",{pre:!0,attrs:{class:"language-ts"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// Prints:")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//    1")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//    2")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//    3")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Foo")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" prop "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("console")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("log")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Foo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prop"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("console")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("log")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Foo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prop"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token builtin"}},[t._v("console")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("log")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("Foo"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("prop"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("++")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n  "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])])]),a("p",[t._v("感谢 "),a("a",{attrs:{href:"https://github.com/Kingwl",target:"_blank",rel:"noopener noreferrer"}},[t._v("Wenlu Wang"),a("OutboundLink")],1),t._v(" 为 TypeScript 添加了该支持。\n更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/43370",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h2",{attrs:{id:"tsc-help-更新与优化"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#tsc-help-更新与优化"}},[t._v("#")]),t._v(" "),a("code",[t._v("tsc --help")]),t._v("  更新与优化")]),t._v(" "),a("p",[t._v("TypeScript 的  "),a("code",[t._v("--help")]),t._v("  选项完全更新了！\n感谢 "),a("a",{attrs:{href:"https://github.com/ShuiRuTian",target:"_blank",rel:"noopener noreferrer"}},[t._v("Song Gao"),a("OutboundLink")],1),t._v("，我们"),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/44409",target:"_blank",rel:"noopener noreferrer"}},[t._v("更新了编译选项的描述"),a("OutboundLink")],1),t._v("和 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/44157",target:"_blank",rel:"noopener noreferrer"}},[a("code",[t._v("--help")]),t._v("  菜单的配色样式"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://devblogs.microsoft.com/typescript/wp-content/uploads/sites/11/2021/08/tsc-help-ps-wt-4-4.png",alt:"The new TypeScript  menu where the output is bucketed into several different areas"}})]),t._v(" "),a("p",[t._v("更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/issues/44074",target:"_blank",rel:"noopener noreferrer"}},[t._v("Issue"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h2",{attrs:{id:"性能优化"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#性能优化"}},[t._v("#")]),t._v(" 性能优化")]),t._v(" "),a("h3",{attrs:{id:"更快地生成声明文件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#更快地生成声明文件"}},[t._v("#")]),t._v(" 更快地生成声明文件")]),t._v(" "),a("p",[t._v("TypeScript 现在会缓存下内部符号是否可以在不同上下文中被访问，以及如何显示指定的类型。\n这些改变能够改进 TypeScript 处理复杂类型时的性能，尤其是在使用了  "),a("code",[t._v("--declaration")]),t._v("  标记来生成  "),a("code",[t._v(".d.ts")]),t._v("  文件的时候。")]),t._v(" "),a("p",[t._v("更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/43973",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h3",{attrs:{id:"更快地标准化路径"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#更快地标准化路径"}},[t._v("#")]),t._v(" 更快地标准化路径")]),t._v(" "),a("p",[t._v("TypeScript 经常需要对文件路径进行 “标准化” 操作来得到统一的格式，以便编译器能够随处使用它。\n它包括将反斜线替换成正斜线，或者删除路径中间的  "),a("code",[t._v("/./")]),t._v("  和  "),a("code",[t._v("/../")]),t._v("  片段。\n当 TypeScript 需要处理成千上万的路径时，这个操作就会很慢。\n在 TypeScript 4.4 里会先对路径进行快速检查，判断它们是否需要进行标准化。\n这些改进能够减少 5-10% 的工程加载时间，对于大型工程来讲效果会更加明显。")]),t._v(" "),a("p",[t._v("更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/44173",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v(" 以及 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/44100",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h3",{attrs:{id:"更快地路径映射"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#更快地路径映射"}},[t._v("#")]),t._v(" 更快地路径映射")]),t._v(" "),a("p",[t._v("TypeScript 现在会缓存构造的路径映射（通过  "),a("code",[t._v("tsconfig.json")]),t._v("  里的  "),a("code",[t._v("paths")]),t._v(" ）。\n对于拥有数百个路径映射的工程来讲效果十分明显。\n更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/44078",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h3",{attrs:{id:"更快地增量构建与-strict"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#更快地增量构建与-strict"}},[t._v("#")]),t._v(" 更快地增量构建与  "),a("code",[t._v("--strict")])]),t._v(" "),a("p",[t._v("这曾是一个缺陷，在  "),a("code",[t._v("--incremental")]),t._v("  模式下，如果启用了  "),a("code",[t._v("--strict")]),t._v("  则 TypeScript 会重新进行类型检查。\n这导致了不管是否开启了  "),a("code",[t._v("--incremental")]),t._v("  构建速度都挺慢。\nTypeScript 4.4 修复了这个问题，该修复也应用到了 TypeScript 4.3 里。")]),t._v(" "),a("p",[t._v("更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/44394",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h3",{attrs:{id:"针对大型输出更快地生成-source-map"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#针对大型输出更快地生成-source-map"}},[t._v("#")]),t._v(" 针对大型输出更快地生成 Source Map")]),t._v(" "),a("p",[t._v("TypeScript 4.4 优化了为超大输出文件生成 source map 的速度。\n在构建旧版本的 TypeScript 编译器时，结果显示节省了 8% 的生成时间。")]),t._v(" "),a("p",[t._v("感谢 "),a("a",{attrs:{href:"https://github.com/dmichon-msft",target:"_blank",rel:"noopener noreferrer"}},[t._v("David Michon"),a("OutboundLink")],1),t._v(" 提供了这项"),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/44031",target:"_blank",rel:"noopener noreferrer"}},[t._v("简洁的优化"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h3",{attrs:{id:"更快的-force-构建"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#更快的-force-构建"}},[t._v("#")]),t._v(" 更快的  "),a("code",[t._v("--force")]),t._v("  构建")]),t._v(" "),a("p",[t._v("当在工程引用上使用了  "),a("code",[t._v("--build")]),t._v("  模式时，TypeScript 必须执行 “是否更新检查” 来确定是否需要重新构建。\n在进行  "),a("code",[t._v("--force")]),t._v("  构建时，该检查是无关的，因为每个工程依赖都要被重新构建。\n在 TypeScript 4.4 里， "),a("code",[t._v("--force")]),t._v("  会避免执行无用的步骤并进行完整的构建。\n更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/43666",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("。")]),t._v(" "),a("h2",{attrs:{id:"javascript-中的拼写建议"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#javascript-中的拼写建议"}},[t._v("#")]),t._v(" JavaScript 中的拼写建议")]),t._v(" "),a("p",[t._v("TypeScript 为在 Visual Studio 和 Visual Studio Code 等编辑器中的 JavaScript 编写体验赋能。\n大多数情况下，在处理 JavaScript 文件时，TypeScript 会置身事外；\n然而，TypeScript 经常能够提供有理有据的建议且不过分地侵入其中。")]),t._v(" "),a("p",[t._v("这就是为什么 TypeScript 会为 JavaScript 文件提供拼写建议 - 不带有  "),a("code",[t._v("// @ts-check")]),t._v("  的 文件或者关闭了  "),a("code",[t._v("checkJs")]),t._v("  选项的工程。\n即，TypeScript 文件中已有的 "),a("em",[t._v('"Did you mean...?"')]),t._v(" 建议，现在它们也作用于 JavaScript 文件。")]),t._v(" "),a("p",[t._v("这些拼写建议也暗示了代码中可能存在错误。\n我们在测试该特性时已经发现了已有代码中的一些错误！")]),t._v(" "),a("p",[t._v("更多详情请参考 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/44271",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v("！")]),t._v(" "),a("h2",{attrs:{id:"内嵌提示-inlay-hints"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#内嵌提示-inlay-hints"}},[t._v("#")]),t._v(" 内嵌提示（Inlay Hints）")]),t._v(" "),a("p",[t._v("TypeScript 4.4 支持了"),a("em",[t._v("内嵌提示")]),t._v("特性，它能帮助显示参数名和返回值类型等信息。\n可将其视为一种友好的 “ghost text”。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://devblogs.microsoft.com/typescript/wp-content/uploads/sites/11/2021/08/inlayHints-4.4-rc-ghd.png",alt:"A preview of inlay hints in Visual Studio Code"}})]),t._v(" "),a("p",[t._v("该特性由 "),a("a",{attrs:{href:"https://github.com/Kingwl",target:"_blank",rel:"noopener noreferrer"}},[t._v("Wenlu Wang"),a("OutboundLink")],1),t._v(" 的 "),a("a",{attrs:{href:"https://github.com/microsoft/TypeScript/pull/42089",target:"_blank",rel:"noopener noreferrer"}},[t._v("PR"),a("OutboundLink")],1),t._v(" 所实现。")]),t._v(" "),a("p",[t._v("他也在 "),a("a",{attrs:{href:"https://github.com/microsoft/vscode/pull/113412",target:"_blank",rel:"noopener noreferrer"}},[t._v("Visual Studio Code 里进行了集成"),a("OutboundLink")],1),t._v(" 并在 "),a("a",{attrs:{href:"https://code.visualstudio.com/updates/v1_59#_typescript-44",target:"_blank",rel:"noopener noreferrer"}},[t._v("July 2021 (1.59) 发布"),a("OutboundLink")],1),t._v("。\n若你想尝试该特性，需确保安装了"),a("a",{attrs:{href:"https://code.visualstudio.com/updates/v1_59",target:"_blank",rel:"noopener noreferrer"}},[t._v("稳定版"),a("OutboundLink")],1),t._v("或 "),a("a",{attrs:{href:"https://code.visualstudio.com/insiders/",target:"_blank",rel:"noopener noreferrer"}},[t._v("insiders"),a("OutboundLink")],1),t._v(" 版本的编辑器。\n你也可以在 Visual Studio Code 的设置里修改何时何地显示内嵌提示。")]),t._v(" "),a("h2",{attrs:{id:"自动导入的补全列表里显示真正的路径"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#自动导入的补全列表里显示真正的路径"}},[t._v("#")]),t._v(" 自动导入的补全列表里显示真正的路径")]),t._v(" "),a("p",[t._v("当 Visual Studio Code 显示补全列表时，包含自动导入在内的补全列表里会显示指向模块的路径；\n然而，该路径通常不是 TypeScript 最终替换进来的模块描述符。\n该路径通常是相对于 "),a("em",[t._v("workspace")]),t._v(" 的，如果你导入了  "),a("code",[t._v("moment")]),t._v("  包，你大概会看到  "),a("code",[t._v("node_modules/moment")]),t._v("  这样的路径 。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://devblogs.microsoft.com/typescript/wp-content/uploads/sites/11/2021/08/completion-import-labels-pre-4-4.png",alt:"A completion list containing unwieldy paths containing 'node_modules'. For example, the label for 'calendarFormat' is 'node_modules/moment/moment' instead of 'moment'."}})]),t._v(" "),a("p",[t._v("这些路径很难处理且容易产生误导，尤其是插入的路径同时需要考虑 Node.js 的  "),a("code",[t._v("node_modules")]),t._v("  解析，路径映射，符号链接以及重新导出等。")]),t._v(" "),a("p",[t._v("这就是为什么 TypeScript 4.4 中的补全列表会显示真正的导入模块路径。")]),t._v(" "),a("p",[a("img",{attrs:{src:"https://devblogs.microsoft.com/typescript/wp-content/uploads/sites/11/2021/08/completion-import-labels-4-4.png",alt:"A completion list containing clean paths with no intermediate 'node_modules'. For example, the label for 'calendarFormat' is 'moment' instead of 'node_modules/moment/moment'."}})]),t._v(" "),a("p",[t._v("由于该计算可能很昂贵，当补全列表包含许多条目时最终的模块描述符会在你输入更多的字符时显示出来。\n你仍可能看到基于 workspace 的相对路径；然而，当编辑器 “预热” 后，再多输入几个字符它们会被替换为真正的路径。")])])}),[],!1,null,null,null);s.default=e.exports}}]);