当前位置: 首页 > 科技观察

微软宣布 TypeScript 4.8 正式发布

时间:2023-03-20 11:05:53 科技观察

微软宣布TypeScript4.8正式发布Inferenceoftypesininfertemplatestringtypes[2]--build--watch--incrementalperformanceimprovements[3]Bugswhencomparingobjectandarrayliterals[4]改进了绑定模式的推断[5]文件监视修复(尤其是跨git检出)[6]查找所有引用性能改进[7]从自动导入中排除特定文件[8]正确性修复和主要更改[9]如果您不熟悉TypeScript,您可以在官方网站上了解更多关于TypeScript[10]的信息。它是一种建立在JavaScript之上并为类型添加语法的语言。这些类型让您可以将您的期望和假设放入您的代码中,然后可以由TypeScript类型检查器进行检查。此检查有助于避免拼写错误、调用未初始化的值、混淆函数参数等。类型不仅仅是检查,它们还用于为您提供强大的TypeScript和JavaScript编辑体验,支持代码完成、转到定义、重命名等。我们熟悉的VisualStudio完全是使用TypeScript开发的!要开始使用TypeScript,您可以通过NuGet[11]获取它,或通过以下命令使用npm:npminstall-Dtypescript编辑器支持也可通过下载VisualStudio2022/2019[12]InstallInsidersofVisualStudioCodeVersion获得[13]或按照说明将SublimeText3的包控制[15]与较新版本的TypeScript[14]一起使用。自Beta和RC以来有什么新功能?自其测试版[16]以来,其稳定版本现在支持排除哪些文件被认为是自动导入[17]。Beta发布帖子也没有记录类型签名中未使用的解构别名的中断。此外,无论是测试版还是RC帖子都没有记录关于在TypeScript语法树上放置装饰器的API中断。这些中断现在在正确性修复和重大更改部分中进行了详细说明[18]改进交集类型、联合兼容性和缩小TypeScript4.8改进了对--strictNullChecks的增强,它更改联合类型与交集类型的工作,并利用类型收缩.例如,人们普遍认为unknown接近于{}|空|undefined因为它接受null、undefined和任何其他类型。TypeScript现在可以识别这一点并允许从到赋值。函数f(x:未知,y:{}|null|undefined){x=y;//总是有效y=x;//过去常常出错,现在有效}另一个变体是{}与任何其他对象类型相同Intersect只是简化为该对象类型。这意味着能够像下面那样覆盖NonNullable,因为{}&null和{}&undefined只是被丢弃了。-类型NonNullable=Textendsnull|不明确的?从不:T;+typeNonNullable=T&{};此改进允许像这样减少和分配交集类型,而条件类型目前不能。functionfoo(x:NonNullable,y:NonNullable>){x=y;//总是有效y=x;//过去常常出错,现在有效}这些更改还允许我们在控制流分析和类型缩小方面实现明智的改进。functionnarrowUnknownUnion(x:{}|null|undefined){if(x){x;//{}}否则{x;//{}|空|未定义}}functionnarrowUnknown(x:unknown){if(x){x;//以前是'unknown',现在是'{}'}else{x;//unknown}}我们现在可以在没有任何类型断言的情况下定义以下函数。有关这些改进的更多详细信息,请参见此处[19]。函数throwIfNullable(value:T):NonNullable{if(value===undefined||value===null){throwError("Nullablevalue!");}//曾经失败,因为“T”无法分配给“NonNullable”。//现在缩小到'T&{}'并成功,因为那只是'NonNullable'。returnvalue;}关于推断模板字符串类型的改进TypeScript中的类型推断最近引入了一种向条件类型中的类型变量添加扩展约束的方法。infer//如果元组的第一个元素可分配给“number”,则获取它,//如果找不到则返回“never”。typeTryGetNumberIfFirst=Textends[inferUextendsnumber,...未知[]]?你:从不;如果这些推断类型出现在模板字符串类型中并且仅限于原始类型,TypeScript现在将尝试解析文字类型。//SomeNum曾经是'number';现在是'100'.typeSomeNum="100"extends`${inferUextendsnumber}`?U:never;//SomeBigInt曾经是'bigint';现在是'100n'.typeSomeBigInt="100"extends`${inferUextendsbigint}`?U:never;//SomeBool曾经是'boolean';现在它是'true'.typeSomeBool="true"extends`${inferUextendsboolean}`?你:从不;这现在可以更好地传达库将在运行时执行的操作并提供更精确的输入。有关此功能的更多信息,请参见此处[20]。--build,--watch,--incrementalperformanceimprovementsTypeScript4.8引入了优化,现在可以避免在对模式进行无操作更改期间花费时间更新时间戳,这使得重建速度更快,并避免了与其他监视TypeScript输出的构建工具混淆的问题。在Microsoft生成的一个相当大的内部代码库中,他们看到许多简单的常见操作的时间减少了10%-25%,在没有变化的情况下减少了大约40%,而在TypeScript代码库中也看到了类似的结果。可以在GitHub[21]上查看更改和性能结果。比较对象和数组字面量时的bug在JavaScript中,通常==或===只能检查对象(和数组)之间的两个引用是否指向相同的值而不能判断值是否相等,团队认为这是可能造成的一些bug生产代码。TypeScript目前不允许像下面这样的代码。if(peopleAtHome===[]){//~~~~~~~~~~~~~~~~~~~//这个条件总是返回“false”,因为JavaScript通过引用比较对象,而不是值。console.log("here'swhereIlie,brokeninside.(x:T,y:T):T;let[a,b,c]=chooseRandomly([42,true,"hi!"],[0,false,"bye!"]);//^^^//|||//||字符串//||//|boolean//|//number更多信息可以查看GitHub上的变化。[23]文件监视修复(尤其是跨gitcheckout)TypeScript很难在监视模式和编辑器场景中修改某些文件,有时症状是陈旧或不准确的错误,可能需要重新启动tsc或VSCode。如果您使用vim在Unix系统上保存文件或在git中交换分支,就会经常发生这种情况。这是由于关于Node.js如何跨文件系统处理重命名事件的假设。Linux和macOS使用的文件系统使用inode[24],而Node.js会将文件观察器附加到inode而不是文件路径[25]。因此,当Node.js返回一个观察者对象[26]时,观察的是路径还是inode取决于平台和文件系统。如果TypeScript检测到路径仍然存在于磁盘上,它会尝试重用同一个观察者对象,这是为了提高效率,但这正是它导致问题的地方,因为即使文件仍然存在于该路径上,它也可能已经被创建了不同的文件,该文件将具有不同的索引节点。因此TypeScript最终重用了watcher对象,而不是在原始位置安装新的watcher并监视可能完全不相关的文件中的更改。所以TypeScript4.8现在可以在inode系统上处理这些情况,并正确安装新的watcher并修复这个问题。可以在此处查看针对文件监控的特定修复[27]。Find-All-References性能改进TypeScript现在在编辑器中运行find-all-references时更智能地聚合引用。这将TypeScript在其自己的代码库中搜索广泛使用的标识符的时间减少了大约20%。有关改进的更多信息,请参见此处[28]。从自动导入中排除特定文件TypeScript4.8引入了一个编辑器首选项,用于从自动导入中排除文件。在VisualStudioCode中,文件名或glob可以添加到“自动导入文件排除模式”下的设置UI中,或添加到.vscode/Settings中。json文件:{//请注意,也可以为JavaScript指定`javascript.preferences.autoImportFileExcludePatterns`。"typescript.preferences.autoImportFileExcludePatterns":["**/node_modules/@types/node"]}这无法避免编译当您包含某些模块或库时很有用,但实际上并不希望它们被导入。可能有许多这样的模块会污染自动导入列表并使其更难自动导出,而此选项在这些情况下可以提供帮助。您可以在此处查看有关实现的更多详细信息[29]。正确性修复和重大更改由于类型系统更改的性质,可以进行的更改很少不会影响某些代码;但是,某些更改更有可能需要对现有代码进行调整。lib.d.ts更新虽然TypeScript努力避免大的破坏,但即使是对内置库的小改动也可能导致问题。我们不希望DOM和lib.d.ts更新导致重大中断,但一个显着的变化是Errors的cause属性现在是未知类型而不是Error。不受约束的泛型不再分配给{}在TypeScript4.8中,对于启用了strictNullChecks的项目,TypeScript现在会正确地发出错误。这将包括任何需要{}、对象或具有所有可选属性的对象的类型。一个简单的例子//接受任何非空非未定义的值函数bar(value:{}){Object.keys(value);//此调用在运行时抛出null/undefined。}//无约束类型参数T...functionfoo(x:T){bar(x);//以前是允许的,现在是4.8的错误。//~//错误:“T”类型的参数不可分配给“{}”类型的参数。}foo(undefined);如上所示,这样的代码有一个潜在的错误nullundefinedvalues可以通过这些不受约束的类型参数间接传递给不应该观察这些值的代码。这种行为也将在类型位置可见,例如:interfaceFoo{x:Bar;}interfaceBar{}不想处理null的现有代码可以通过传播适当的修复约束来定义。-functionfoo(x:T){+functionfoo(x:T){另一种解决方法是在运行时检查null和undefined。functionfoo(x:T){+if(x!==null&&x!==undefined){bar(x);+}}如果您知道由于某种原因通用值不能为null或undefined,您只能使用非空断言。函数foo(x:T){-bar(x);+bar(x!);有关更多信息,您可以查看引入此[30]的更改以及这篇关于无约束泛型现在如何工作的文章专门讨论该问题[31]。装饰器放在修饰符上TypeScript的语法树TypeScript暴露了一个新的类型别名,叫做ModifierLike,它是一个Modifier或者Decorator。导出类型ModifierLike=Modifier|装潢师;有关更多信息,请参阅周围的更改TreeNodeReorganization[32]Deprecations[33]ExposingPredicateFunctions[34]Unabletoimport/exporttypesinJavaScriptfilesTypeScriptpreviouslyallowedJavaScriptfilesImportingandexportingentitieswithtypedeclarationsbutnovalues在import和export语句中是不正确的行为,因为命名的imports和exports不存在的值将导致ECMAScript模块下的运行时错误。当JavaScript文件在--checkJs下或通过//@ts-check注释进行类型检查时,TypeScript现在会发出错误。//@ts-check//将在运行时失败,因为'SomeType'不是value.import{someValue,SomeType}from"some-module";/***@type{SomeType}*/exportconstmyValue=someValue;/***@typedef{字符串|number}MyType*///将在运行时失败,因为“MyType”不是value.export{MyTypeasMyExportedType};要从另一个模块引用类型,您可以直接限制导入。-从“某些模块”导入{someValue,SomeType};+从“某些模块”导入{someValue};/**-*@type{SomeType}+*@type{import("some-module").SomeType}*/exportconstmyValue=someValue;要导出类型,只需/**@typedef*/使用JSDoc中的注释。@typedef注释已经自动从它们包含的模块中导出类型。/***@typedef{字符串|number}MyType*/+/**+*@typedef{MyType}MyExportedType+*/-export{MyTypeasMyExportedType};有关更改的更多信息,请参阅此处[35]。绑定模式中未使用的重命名现在是类型签名中的错误TypeScript的类型注释语法通常在解构值时似乎有效。例如,采用以下功能。声明函数makePerson({name:string,age:number}):Person;阅读此签名,您可能会认为makePerson显然接受一个具有字符串类型的名称属性和数字类型的年龄属性的对象。然而makePerson,虽然它确实说它会接受一个具有name和age属性的对象,但没有为它们指定类型,它只是说它将name和age分别重命名为字符串和数字。在纯类型结构中,编写这样的代码是无用的,而且通常是错误的,因为开发人员通常认为他们在编写类型注释。除非稍后在签名中引用,否则TypeScript4.8会出现这些错误。上面签名的正确写法如下:数}):人;在此处阅读更改[36]。下一步是什么?TypeScript目前正在开发4.9版。有关此版本的详细时间表和计划的功能,您可以查看TypeScript4.9迭代计划[37]。最后,希望TypeScript团队能够实现让编码快乐的愿景~