//@ts-check
で JS を書いていて、
as any as
とか as unknown as
とか
(window as any).hoge
とかみたいな書き方がしたくなったので調べた。
ふつうはこうなる
//@ts-check
document.createElement("div").innerText = 12345;
// -> Type 'number' is not assignable to type 'string'. ts(2322)
TypeScript ならこれでゴリ押せる
document.createElement("div").innerText = 12345 as any as string;
document.createElement("div").innerText = 12345 as unknown as string;
でも JSDoc では当然このような書き方はできない・・・
ts-expect-error
は代案にならない
TypeScript では as any as
を使用することで、以下のように変数の型をそのまま変更できるが
const value = 12345 as any as string;
type X = typeof value;
// -> type X = string
@ts-expect-error
はエラーを無視するだけなので、変数の型は変化しない。
const value = 12345;
//-> const value: 12345
//@ts-expect-error
document.createElement("div").innerText = value;
だから @ts-expect-error
を as any as
と同じように使うことはできない。
JSDoc の @type
だとエラる
//@ts-check
/** @type {string} */
const value = 12345;
// -> Type 'number' is not assignable to type 'string'. ts(2322)
document.createElement("div").innerText = value;
これが JSDoc の正解
といっても、あまりスマートじゃないし裏技じみてるが。
//@ts-check
/**
* @template T
* @param {(type: T) => any} def
* @param {unknown} from
* @returns {T}
*/
const resolveTypeAs = (def, from) =>
//@ts-expect-error
from;
const value = resolveTypeAs(
/** @param {string} _ */ (_) => _,
12345
);
// -> const value: string
document.createElement("div").innerText = value;
resolveTypeAs
という、型を強制的に書き換える関数を作る。
第一引数で @param
に無名関数の引数として T
となる型を渡す形にした。