として“スクリプト”トリック


数年前、私が最初にタイプスクリプトを学んだとき、私はこのようなものを見たどこかでチュートリアルのスニペットを見つけました.
const myArray = ['hello','world',10] as const;
変な、右?明らかにそれはconstですので、何がas constのポイントですか?
VSCODEのようなタイプスクリプトを意識したエディタを使用する場合、これらの2つのケースのホバーテキスト型が完全に異なることがわかります.
// shows up as: `const myArray: (string | number)[]`
const myArray = ['hello','world',10];

// shows up as: `const myArray: readonly ["hello", "world", 10]`
const myArray = ['hello','world',10] as const;
最初のケースでは、配列をconstとして扱い、typescriptはどのようなものがどの配列に入るのかを十分に推論します.
番目のケースでは、全体が一定になるので、そのreadonlyフラグを取得し、その配列に正確な順序で入力する正確なものを参照してください!
では、なぜこれは有用ですか?
残念なことに、これはtypescriptのas const配列のmutatorsを使用するのを防ぐことができません(例えば、あなたが.push()に何かを試みるならば、typScriptは動揺しません).あなたがObject.freezeでそれを包むならば、それはうそです.
しかし、非常に有用であることがわかったのは、定義されたオブジェクトキーのサブセットを繰り返します.
const myObject = {
  hello: 'world',
  number: 10,
  anArray: [1,2,3],
  nested: {something: 'else'}
}

// Without using `as const`:
for(const field of ['hello','world']){
  // The type of `field` is just 'string'
}

// With `as const`:
for(const field of ['hello','world'] as const){
  // The type of `field` is 'hello'|'world'
}
正確で一般的なタイプ情報を持つことの違いは、タイプスクリプトで難しいか簡単である何かの間のすべての違いを作ることができます.
残念ながら、JSdocsはこれをサポートしていないので、バニラJavaScriptでこのトリックを使用すると、回避策が必要になります.
/** Thanks to {@link https://github.com/microsoft/TypeScript/issues/30445#issuecomment-671042498} */

/**
 * Identity function. Coerces string/number literals to value-as-type.
 * @template {string|number} T
 * @param {T} v
 * @return {T}
 */
function toConst(v) {
  return v;
}

const five = toConst(5);
// --> Type shows up as 5 instead of "number"

/**
 * Creates an array from the given arguments, type as a constant tuple.
 * @template {(string|number)[]} T
 * @param {T} v
 * @return {T}
 */
function toConstTuple(...v) {
  return v;
}

const tuple = toConstTuple("Hello","World",10);
// --> Type shows up as ["Hello","World",10] instead of (string|number)[]
TypesScript言語サーバに読み取り専用型を与えることは、何もしない関数で値をラップするのはちょっと奇妙です.しかし、少なくともこれらの限られたケースのために動作します.