1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JSDoc @templateの使い方

Last updated at Posted at 2024-04-02

VSCodeでJavascriptを使うときの型推論の話です。
ほとんど箇条書きですが、簡単なサンプルを併記しているので それほど難しくはないかと思います。

関数で使える

関数を実行するときに実際に渡した引数の型をベースにして型を推測してくれるようになります。
templateの記述が無いときは、any型になります。

/**
 * @template T
 * @param {T} value 
 */
function foo (value) {
  return value;
}

let a = foo(1); // number
let b = foo(''); // string

クラスでも使える

関数だけではなく、クラスでも使えます。

/**
 * @template T
 */
class Bar {
  /**
   * @param {T} value
   */
  constructor (value) {
    this.value = value;
  }

  baz () {
    return this.value;
  }
}

let bar = new Bar(0);
let foo = bar.baz(); // number

型注釈をつけるときは<>で指定できます。

/** @type {Bar<number>} */
let bar = new Bar(0);

Javascript標準の Array や Set はこれに該当します。
例: Array<string>, Set<number>

2つ以上宣言できる

Javascript標準の Object や Map はこのパターンです。
例: Object<string, any>, Map<number, boolean>

/**
 * @template T
 * @template U
 */
class Dictionary {
  /**
   * @param {T} key
   * @param {U} value
   */
  set (key, value) {}
}

/** @type {Dictionary<string, number>} */
let dic = new Dictionary();
dic.set('width', 100);

ベースとなる型を指定できる

template と T の間に型注釈を入れれば、型を限定することができます。

/**
 * @template {string} T
 * @param {T} value
 */
function hoge (value) {
  return value;
}

let valA = '';
let hogeA = hoge(valA); // string

let valB = 0;
let hogeB = hoge(valB); // これは警告される

// ベースよりも限定的な型は問題なく使える
/** @type {'A' | 'B'} */
let valC;
let hogeC = hoge(valC); // "A" | "B"

発展的な使い方

その1 返り値の型補完

/**
 * @template T
 * @template U
 */
class Dictionary {
  /**
   * @returns {Array<T>}
   */
  keys () { return []; }

  /**
   * @returns {Array<U>}
   */
  values () { return []; }
}

/** @type {Dictionary<string, number>} */
let dic = new Dictionary();
let keys = dic.keys(); // string[]
let values = dic.values(); // number[]

その2 keyofとの併用

引数のプロパティをkeyofで抽出しています。

/**
 * @template {Object<string, any>} T
 */
class ValueReader {
  /**
   * @param {T} obj
   */
  constructor (obj) {
    this.obj = obj;
  }

  /**
   * @param {keyof T} key
   */
  read (key) {
    return this.obj[key];
  }
}

let reader = new ValueReader({ id: '01', name: 'white' });
// readの引数が "id" | "name" になる
let id = reader.read('id');

雑感など

keyof や extends と組み合わせれば、インテリセンスをよりリッチにすることができます。
使いどころは探せばあるので、試してみてください。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?