JSDocでよくね?
綾坂こと.icon
// @ts-checkが通用するのはVSCodeのみbsahd.icon
そうなんだ…… 現代でJavaScriptをVSCode以外で書く人間いるのか……?綾坂こと.icon
2021年くらいまではscrapboxでJavaScript書いてましたtakker.icon
1年前くらいから今までずっとdevelopertoolでしか書いてないik.icon
コードの途中に型情報を書くなという気持ちになる綾坂こと.icon
わからないbsahd.iconMijinko_SD.icon
トランスパイルしたらどの道型情報外れるよ(暴論)Mijinko_SD.icon やはりDeno.icon君しか勝たんtakker.iconbsahd.icon
code:example.ts
function add(left: number, right: number): number {
return left + right;
}
code:example.js
/**
* 「型についての情報が書かれている部分」と「ロジックが書かれている部分」は分離されてたほうがわかりやすいと思う
* @param {number} left - 左項
* @param {number} right - 右項
* @returns {number} - 和
*/
function add(left, right) {
return left + right;
}
「この関数は数値leftと数値rightを取ってleft+rightを返します。」より「leftは数値、rightは数値です。この関数はleft+rightを返します。」になってたほうが嬉しいな〜と個人的に思っている綾坂こと.icon
個人の好みだとは思うけれどやっぱりよくわからないMijinko_SD.icon
一番最初に見たものから離れられてないだけじゃないかな
「型についての情報が書かれている部分」と「ロジックが書かれている部分」は分離されてたほうがわかりやすくなっているとは感じないので興味深いtakker.icon
考えたことなかったので面白い
どういうところがわかりやすくなったと感じているのか知りたい
おもしろい、一理あるかもしれないmrsekut.icon
ただ、タイトルの「JSDocでよくね?」はsyntaxの話と、型の有用性の話が混じっている気もする
やりたければ、TypeScriptでも型だけ定義して、あとから実装に紐づけることもできる
code:ts
type Add = (left: number, right: number) => number;
const add: Add = (left, right) => left + right;
こうすれば、コードの途中に型情報は書いていない(?)
(コードってどこ?というのはある)
(こう書いたときに綾坂こと.iconの要求を満たせているのかわからない)
これいいかも綾坂こと.icon
関数名を型名にも使わなきゃいけないのがちょっと気になるが、これは私にとって読みやすい
ただ、結局leftとrightと返り値が何を表すのかをコメントで書くだろうと思うとJSDocでよくね?に戻ってくる 更にわかり易い例で言えば、型定義ファイル.d.tsもある
あれは実装と型を完全に別ファイルに書いているので、コードの途中に型が書かれない
別ファイルに書かれると困るかも綾坂こと.icon
近く(できれば隣)に書いてあって欲しいけど、完全に一緒に書かれていてほしくない
果たしてあれが本当にわかりやすいと言えるだろうか
TypeScriptユーザがJSDocよりもTypeScriptを好むのは
そちらの方が記述量が少ない (syntax関連)
そちらの方が表現できる幅が広い (型の有用性)
とかそういうのが大きいと思う
要求しているモノが同じなら、コメント内に書くかどうかはそこまで重要ではないmrsekut.icon
syntaxの方は慣れとか好みの影響が大きい思う
TypeScriptをバリバリ好んで使う人にとっては、JSDocの表現力が自分の要求に全く届いていないから使っていないだけ
JSDocで十分ならそれで良い
TSユーザが小さいプログラムにも(JSDocではなく)TSを使うのは、
単にJSDocの記法を別途覚えるのが面倒、
プログラムが大きくなったときにTSに切り替えるのが面倒
とかそんな感じではないだろうか
更に、他の言語にまで話を展開するなら、型は実行時にも読まれる言語のほうが多いmrsekut.icon
その場合、コメントみたいに離れた世界にあるよりも、
同一のコードとして存在していたほうが処理系視点で扱いやすい
とかもありそう
JSにおいてもclass定義は型のようなもので、
ではこれを「コードから分離して書く」ならどうなるのか?というのは気になる
TypeScriptの機能性を知らないのか、ただ単に型定義の恩恵を知らないのか、どっちなんだMijinko_SD.icon
ちなみにMijinko_SD.iconは最初は型定義いらないやんって思ってた(今は違う)
型定義が無いと、そもそもその関数が入力に何を求めていて何を出力するのかさっぱりわからないよね…?
そもそもその関数が入力に何を求めていて何を出力するのかさっぱりわからない←同意 綾坂こと.icon
TypeScriptは結構厳密に型チェックしてくれるし、連想配列の型(interface, type, 他の言語で言う構造型)をUtility型を使うとかして部分的に変更して使い回すこともできる 厳密に型定義されると何が良いかと言うと、ぬるぽ(JSで言うTypeError)のような実行時エラーをコード実装時に気づくことができるため、開発効率が格段に上がること 部分的に変更できて何が良いかと言うと、型の柔軟性が高いからより厳密な型もより簡単に(回りくどいことをせずに)組めるということ
逆にJSDocを読み取るタイプの型チェッカーがどこまでできるのか知らないけれど、こういうことはできるのかな
code:possibleNull.ts
const foo = () => {
interface aryType {id: number, value?: unknown}
const possibleNull: aryType | undefined = ary.find(e => e.id === 1)
// この時点ではpossibleNullはaryType | undefined型扱い
if (!possibleNull) return
// このif文より下は、possibleNullはaryType扱いとなる(undefinedが消える)
// undefinedの可能性は消えたため、そのまま呼び出してもエラーにならない
console.log(possibleNull.id ** 10)
}
foo()
↓実行コマンド
型チェッカーの厳密度によると思うけれど、これができないなら厳密さの面でTypeScriptの方が勝るということになる
こういうことか……?綾坂こと.icon
https://gyazo.com/f271de560904803aac565bfd7a764558
左の赤波線部分は「'possibleNull' は 'undefined' の可能性があります。」
code:possibleNull.js
// @ts-check
/**
* @typedef {Object} AryType
* @prop {number} id
* @prop {unknown} value
*/
const foo = () => {
/** @type {AryType[]} */
/** @type {AryType|undefined} */
const possibleNull = ary.find(a => a.id === 1);
if (!possibleNull) return;
console.log(possibleNull.id ** 10);
};
foo();
JSDocで表現できない型がいくつかあるtakker.icon
無視していいエッジケース
readonlyとかas constとかas Typeなどの表現もできなかったはず これは方法を知らないだけかもしれない
できない気がする、TypeScriptってそんなことできたんだ綾坂こと.icon
強いてあげるならObject.freeze()で凍結してミスってたらエラー吐かせるくらい?
コンパイル時に済ませたいのとbundle sizeを大きくしたくないのとで、なるべく型で制約をかけたいtakker.icon JSDocはオブジェクトのプロパティの型もかけるので、まあいいか……となる綾坂こと.icon
code:example.js
/** @type {{ name: string, age: number }} */
const userInfo = {
"name": "山田太郎",
"age": 18,
};
これでreadonlyできるかもtakker.icon
/** @type {Readonly<{ name: string, age: number }>} */は通るはずだし
知見takker.icon
いやできるんか〜い綾坂こと.icon
この辺の記事も詳しいmrsekut.icon
見覚えある記事だtakker.icon
逆にこれらのトリッキーな型パズルさえ使わなければJSDocで十分
関数の出入りのタイミングでしか型の情報を表明できないのがなーnishio.icon
名前が定義されるタイミングでそれの型も定義されてて欲しくない?
@typeのこと……?綾坂こと.icon
code:example.js
/** @type {string} ユーザーの入力 */
const userInput = window.prompt();
Javaから入った身としては型宣言が無いのが怖くて仕方ないik.icon
拡張機能いくつか作ったから大分慣れたけどそれでも少し大きな拡張機能作るときは型宣言が無いと心配になる
まあ無い分の融通も受けてはいるんだけれども…
classベースで書かれた型無しJS libraryを読むとき苦労したtakker.icon
引数に何が入ってくるのか特定が非常に困難
deno非対応のライブラリだと妥協でjsdocにすることはあるが...bsahd.icon
今日deno+tsを使い始める => 井戸端にはts否定記事が書かれている
Pythonから入った身としてはコード内に型情報が入ることに特に違和感はない
(PythonではTSと同様の記法で型注釈をいれる)
表記的にすごく似ている
deno.iconts.iconTypeScript使って
これ見たい 綾坂こと.icon
実際はTypeScriptがいい理由よりJavaScriptがダメな理由を挙げる方が楽な気がするMijinko_SD.icon
知りたいのは"JSDocがダメな理由"かも 綾坂こと.icon
JavaScriptのダメなところを解消するためにはJSDocでは不十分だが、TypeScriptは十分であるとする理由
(素の)JavaScriptがダメなのはわかる
jsrだとentry pointsのJSファイルには必ず.d.tsが必要で、JSDocが認識されないtakker.icon JSDocを認識させるissueは立っているが、活動していない
JSで書くと、transpileせずにそのままbrowserで読み込める利点はあるtakker.icon
githubにあるコードの直リンクをimportできる
とはいえ、transpile不要という特徴が生かされる場面はあまり思いつかない
scrapbox内でコードを書く場合は重宝するかも
Scrapbox国会Scrapbox内でコードを書くのは今日から禁止ですwho.icon
そのまま読み込めると外への公開が楽だな〜とは思っているかも綾坂こと.icon
GitHub Pagesとかは自動でtranspileやってくれると認識しているので、それが強い理由かと言われると微妙
現状トランスパイル不要の利点はまあまあ活かせるけれどMijinko_SD.icon
最近だとNode.jsがTypeScriptにネイティブ対応しようとしてるという話もあるし そのうちブラウザ内で直接TypeScriptが実行できるようになる気もする
(2024-09-19)ただ進展はそんなにない
難航してるっぽい
もしかして実行前だけでなく実行時もチェックしようとしてる??Mijinko_SD.icon
そうであれば難航するのも頷ける
型注釈部分を無視してよければそんなにむずくなさそう綾坂こと.icon