起こった現象
Node.js で @google-cloud/bigquery
を利用していると、ある日突然このような型エラーが発生するようになった。
node_modules/@google-cloud/paginator/build/src/resource-stream.d.ts:37:5 - error TS2416: Property 'end' in type 'ResourceStream<T>' is not assignable to the same property in base type 'Transform'.
Type '(...args: any[]) => void' is not assignable to type '{ (cb?: (() => void) | undefined): this; (chunk: any, cb?: (() => void) | undefined): this; (chunk: any, encoding?: BufferEncoding | undefined, cb?: (() => void) | undefined): this; }'.
Type 'void' is not assignable to type 'this'.
'this' could be instantiated with an arbitrary type which could be unrelated to 'void'.
37 end(...args: any[]): void;
~~~
原因は @types/node
の https://github.com/DefinitelyTyped/DefinitelyTyped/pull/57473 の変更で、これは readable.destroy()
と readable.end()
の返り値が、Node.js の仕様上は this
であるのに対し、 @types/node
上の型定義だと void
になってしまっている問題を修正するもの。
2022/01/19 時点では @google-cloud/paginator
の型定義がこの変更に追従できておらず、型エラーを起こしてしまっている。
回避策
@types/node
はマイナーバージョンまでは Node.js のバージョンと一致してるが、パッチバージョンは修正があるたびにインクリメントする事になっている。
そのため、この問題を回避するには https://github.com/DefinitelyTyped/DefinitelyTyped/pull/57473 の変更が行われる前の @types/node
のパッチバージョンに固定すると良い(健全ではない)。
具体的には 12.20.39
と 14.18.3
が直前のバージョンに該当する。
よくわからん
@types/node
と Node.js の LTS の関係をよく知らないのでわからなかったけど、この変更は現在の Node.js の LTS であるところの v16 系には含まれていない。なんでなんだろ
PR を出そうと思ったが、 @google-cloud/paginator
の現在の Node.js のバージョンが v16 系になっており、 https://github.com/DefinitelyTyped/DefinitelyTyped/pull/57473 の変更が降ってこないのでどうしたものか……となってしまった
本来はどうなるべきなの?
本来はすべてが Node.js の仕様に準ずる形になるのが妥当ですが、影響範囲が広すぎるので、https://github.com/DefinitelyTyped/DefinitelyTyped/pull/57473#issuecomment-1010494671 でも提案されているように
Base type has relaxed definitions like
end(): this | void
. It might miss some errors of type usage.
あたりの落とし所が実現すると世界が平和になるなあと思います。
追記(2022/01/25)
@types/node
v16 系にもこの型定義の変更を取り込むように提案する PR が作られました
追記
https://github.com/googleapis/nodejs-paginator/issues/308 でこの問題は修正されました!