推荐阅读
ts 4.9 官方文档 #the-satisfies-operator
考虑如下的一个困境:
type RGB = [r: number, g: number, b: number]
type ColorNames = "red" | "green" | "blue"
const color = {
red: [255, 0, 0],
green: '#00FF00',
blue: [0, 0, 255],
}
// 我们一方面希望限制 `color` 为 `Record<ColorNames, RGB | string>`,
// 另一方面又希望保留各属性的实际的值(后面可能会有用),
// 例如:
color.red.map((i) => i / 255)
color.green.toLowerCase()
过去不好实现:
// 尝试 1
const color: Record<ColorNames, RGB | string> = {
// ...
}
color.red.map((i) => i / 255)
// ~~~ 报错,color.red 可能是 RGB | string
// 尝试 2
const color = {
// ...
// 这样不仅无法实现需求,color.red 可能是 RGB | string
// 而且还限制不了此处的多余属性名
// 例如这儿我多写一个 gray: '#666666' 也不会报错
} as Record<ColorNames, RGB | string>
现在引入了 satisfies
操作符
const color = {
red: [255, 0, 0],
green: '#00FF00',
blee: [0, 0, 255],
//~~~~ 这儿拼写错误就会抛错了
gray: '#666666',
//~~~~ 这儿会报错 "gray" was never listed in 'ColorNames'.
} satisfies Record<ColorNames, RGB | string>
ts 5.0 官方文档 #const-type-parameters
我们在需要收紧(narrow)类型的时候,通常会使用 as const
:
interface HasColors {
colors: string[]
}
function getColors<T extends HasColors>(arg: T): T['colors'] {
return arg.colors
}
// Inferred type: string[]
const colors = getColors({
colors: ['RED'],
})
如果我们需要收紧类型(从 string[]
收紧到 ['RED']
),我们会:
// Inferred type: ['RED']
const colors = getColors({
colors: ['RED'],
} as const)
这样是可行的,但是有点麻烦,每次调用 getColors
的时候都要 as const
一下,还容易忘。ts 5.0
现在可以在类型参数声明中添加 const 修饰符,以使 const 推断作为默认值:
interface HasColors {
colors: readonly string[]
// ^^^^^^^^
}
function getColors<const T extends HasColors>(arg: T): T['colors'] {
// ^^^^^
return arg.colors
}
// Inferred type: ['RED']
const colors = getColors({
colors: ['RED'],
})
ts 5.2 官方文档 #using-declarations-and-explicit-resource-management
需要
polyfill
以及tsconfig
设置target
和lib
, 详情见文档。
当我们需要处理文件的时候:
function doSomeWork() {
const path = 'xxx'
const file = fs.openSync(path, 'w+')
// use file...
if (someCondition()) {
// Close the file
fs.closeSync(file)
return
}
// Close the file
fs.closeSync(file)
}
清理工作繁琐还容易遗漏。
现在 ts 引入了 using
关键字和全局类型 Disposable
:
class TempFile implements Disposable {
#path: string
#handle: number
constructor(path: string) {
this.#path = path
this.#handle = fs.openSync(path, 'w+')
}
[Symbol.dispose]() {
// Close the file and delete it.
fs.closeSync(this.#handle)
}
}
function doSomeWork() {
using file = new TempFile('xxx')
// use file...
if (someCondition()) {
// do some more work...
return
}
// 会在“最后”自动执行你声明的 Symbol.dispose 方法
}
dispose
也支持异步(asyncDispose
),更多请看官方文档,或者这篇博文protogenesis: JavaScript-之-using-关键字也写得很完善很详细(但是这篇博文介绍的是提案内容,可能不一定和 ts 当前实现完全一致)。
ts 5.4 官方文档 #preserved-narrowing-in-closures-following-last-assignments
function formatUrl(url: string | URL) {
if (typeof url === 'string') {
url = new URL(url)
}
url.searchParams
// ~~~~~~~~~~~~
}
过去这儿会报错,ts
认为 url
可能是 string
.
现在 ts
会保留我们在 if
中对 url
的类型收紧(显然 url
一定是 URL
)。
如非特别声明,本站作品均为原创,遵循【自由转载-保持署名-非商用-非衍生 创意共享 3.0 许可证】。
对于转载作品,如需二次转载,请遵循原作许可。