TypeScript 5.3

2023-11-30 09:18:01 浏览数 (1)

导入属性

TypeScript 5.3支持导入属性提案的最新更新。

导入属性的一个用例是向运行库提供有关模块预期格式的信息。

代码语言:javascript复制
 // We only want this to be interpreted as JSON, 

 // not a runnable/malicious JavaScript file with a `.json` extension. 
 import obj from "./something.json" with { type: "json" };

这些属性的内容不会被TypeScript检查,因为它们是特定于主机的,并且只是单独留下,以便浏览器和运行时可以处理它们(可能是错误)。

代码语言:javascript复制
 // TypeScript is fine with this. 
 // But your browser? Probably not. 
 import * as foo from "./foo.js" with { type: "fluffy bunny" }; 

动态import()调用也可以通过第二个参数使用导入属性。

代码语言:javascript复制
 const obj = await import("./something.json", { 
 with: { type: "json" } 
 }); 

第二个参数的预期类型由一个名为ImportCallOptions的类型定义,默认情况下,该类型只需要一个名为with的属性。

请注意,导入属性是早期称为“导入断言”的提案的演变 最明显的区别是使用with关键字而不是assert关键字。 但不太明显的区别是,运行时现在可以自由地使用属性来指导导入路径的解析和解释,而导入断言只能在加载模块后断言某些特性。

随着时间的推移,TypeScript将弃用旧的导入断言语法,而支持拟议的导入属性语法。 使用assert的现有代码应该迁移到with关键字。 需要导入属性的新代码应该独占地使用with

我们 我们

稳定支持 resolution-mode 导入类型

在TypeScript 4.7中,TypeScript在resolution-mode中添加了对/// <reference types="..." />属性的支持,以控制是否应该通过importrequire语义解析说明符。

代码语言:javascript复制
 /// <reference types="pkg" resolution-mode="require" /> 
 // or 
 /// <reference types="pkg" resolution-mode="import" /> 

一个相应的字段也被添加到纯类型导入的导入断言中; 然而,它只在TypeScript的夜间版本中得到支持。 理由是,在精神上,导入断言并不打算指导模块解析。 因此,该功能在夜间模式下进行了试验,以获得更多的反馈。

但是考虑到import属性可以指导解析,并且我们已经看到了合理的用例,TypeScript 5.3现在支持resolution-modeimport type属性。

代码语言:javascript复制
 // Resolve `pkg` as if we were importing with a `require()` 
 import type { TypeFromRequire } from "pkg" with { 
 "resolution-mode": "require" 
 }; 
 // Resolve `pkg` as if we were importing with an `import` 
 import type { TypeFromImport } from "pkg" with { 
 "resolution-mode": "import" 
 }; 
 export interface MergedType extends TypeFromRequire, TypeFromImport {} 

这些导入属性也可以用于import()类型。

代码语言:javascript复制
 export type TypeFromRequire = 
 import("pkg", { with: { "resolution-mode": "require" } }).TypeFromRequire; 
 export type TypeFromImport = 
 import("pkg", { with: { "resolution-mode": "import" } }).TypeFromImport; 
 export interface MergedType extends TypeFromRequire, TypeFromImport {} 

欲了解更多信息,请查看此处的更改

resolution-mode 支持所有模块模式

以前,仅允许在resolution-mode选项moduleResolutionnode16下使用nodenext。 为了更容易地查找专门用于类型目的的模块,resolution-mode现在可以在所有其他moduleResolution选项(如bundlernode10)中正常工作,并且在classic下不会出错。

有关详细信息,请参阅实现pull request。

switch (true) 缩小

TypeScript 5.3现在可以基于case中每个switch (true)子句中的条件执行收缩。

代码语言:javascript复制
 function f(x: unknown) { 
 switch (true) { 
 case typeof x === "string": 
 // 'x' is a 'string' here 
 console.log(x.toUpperCase()); 
 // falls through... 
 case Array.isArray(x): 
 // 'x' is a 'string | any[]' here. 
 console.log(x.length); 
 // falls through... 
 default: 
 // 'x' is 'unknown' here. 
 // ... 
 } 
 } 

这个功能是由Mateusz Burzyovski率先开始的 我们想表达一个“谢谢”对于这种贡献。

缩小与布尔值比较的范围

有时候,你可能会发现自己在一个条件下与truefalse进行直接比较。 通常这些都是不必要的比较,但您可能更喜欢它作为一种风格,或者避免围绕JavaScript真实性的某些问题。 无论如何,以前的TypeScript在执行收缩时无法识别这样的表单。

TypeScript 5.3现在在缩小变量时保持并理解这些表达式。

代码语言:javascript复制
 interface A { 
 a: string; 
 } 
 interface B { 
 b: string; 
 } 
 type MyType = A | B; 
 function isA(x: MyType): x is A { 
 return "a" in x; 
 } 
 function someFn(x: MyType) { 
 if (isA(x) === true) { 
 console.log(x.a); // works! 
 } 
 } 

我们

instanceof 缩小范围 Symbol.hasInstance

JavaScript的一个稍微深奥的特性是可以覆盖instanceof操作符的行为。 为此,instanceof操作符右侧的值需要有一个名为Symbol.hasInstance的特定方法。

代码语言:javascript复制
 class Weirdo { 
 static [Symbol.hasInstance](testedValue) { 
 // wait, what? 
 return testedValue === undefined; 
 } 
 } 
 // false 
 console.log(new Thing() instanceof Weirdo); 
 // true 
 console.log(undefined instanceof Weirdo); 

为了在instanceof中更好地建模这种行为,TypeScript现在检查是否存在这样的[Symbol.hasInstance]方法,并将其声明为类型谓词函数。 如果是,则instanceof操作符左侧的测试值将由该类型谓词适当地缩小。

代码语言:javascript复制
 interface PointLike { 
 x: number; 
 y: number; 
 } 
 class Point implements PointLike { 
 x: number; 
 y: number; 
 constructor(x: number, y: number) { 
 this.x = x; 
 this.y = y; 
 } 
 distanceFromOrigin() { 
 return Math.sqrt(this.x ** 2   this.y ** 2); 
 } 
 static [Symbol.hasInstance](val: unknown): val is PointLike { 
 return !!val && typeof val === "object" && 
 "x" in val && "y" in val && 
 typeof val.x === "number" && 
 typeof val.y === "number"; 
 } 
 } 
 function f(value: unknown) { 
 if (value instanceof Point) { 
 // Can access both of these - correct! 
 value.x; 
 value.y; 
 // Can't access this - we have a 'PointLike', 
 // but we don't *actually* have a 'Point'. 
 value.distanceFromOrigin(); 
 } 
 }  

正如你在这个例子中看到的,Point定义了自己的[Symbol.hasInstance]方法。 它实际上充当了一个名为PointLike的单独类型的自定义类型保护。 在函数f中,我们能够用valuePointLike缩小到instanceof,但不能缩小到Point。 这意味着我们可以访问属性xy,但不能访问方法distanceFromOrigin

有关更多信息,您可以在这里阅读有关此更改的信息。

检查 super 实例字段上的属性访问

在JavaScript中,可以通过super关键字访问基类中的声明。

代码语言:javascript复制
 class Base { 
 someMethod() { 
 console.log("Base method called!"); 
 } 
 } 
 class Derived extends Base { 
 someMethod() { 
 console.log("Derived method called!"); 
 super.someMethod(); 
 } 
 } 
 new Derived().someMethod(); 
 // Prints: 
 // Derived method called! 
 // Base method called! 

这与编写类似this.someMethod()的代码不同,因为这可能会调用重写的方法。 这是一个微妙的区别,更微妙的是,如果一个声明从来没有被重写过,这两者通常可以互换。

代码语言:javascript复制
 class Base { 
 someMethod() { 
 console.log("someMethod called!"); 
 } 
 } 
 class Derived extends Base { 
 someOtherMethod() { 
 // These act identically. 
 this.someMethod(); 
 super.someMethod(); 
 } 
 } 
 new Derived().someOtherMethod(); 
 // Prints: 
 // someMethod called! 
 // someMethod called!  

问题是它们可以互换使用,因为super只对在原型上声明的成员有效,而不是实例属性。 这意味着如果你写了super.someMethod(),但是someMethod被定义为一个字段,你会得到一个运行时错误!

代码语言:javascript复制
 class Base { 
 someMethod = () => { 
 console.log("someMethod called!"); 
 } 
 } 
 class Derived extends Base { 
 someOtherMethod() { 
 super.someMethod(); 
 } 
 } 
 new Derived().someOtherMethod(); 
 // 


	

0 人点赞