Typescript これ使ってみて Part 1
はじめに
TypeScriptには新しい機能がたくさん追加されていて、どれを使うか迷うことがあります。本ブログでは、次の開発にすぐ使えそうなTypeScriptの面白い機能をいくつかピックアップして紹介します。
using
キーワードでリソース管理をシンプルに
こちらは C#
の using
や Python
の with
と同じものです。
using
が導入される前は、以下のようにリソース管理を行いました。
export function doSomeWork() {
const path = ".some_temp_file";
const file = fs.openSync(path, "w+");
try {
// use file...
}
finally {
// Close the file and delete it.
fs.closeSync(file);
fs.unlinkSync(path);
}
}
最後に fs.closeSync(file);
や fs.unlinkSync(path);
を忘れてしまうと大変なので、using
キーワードを使えば楽になります。
class TempFile implements Disposable {
[Symbol.dispose]() {
// Close the file and delete it.
fs.closeSync(this.#handle);
fs.unlinkSync(this.#path);
}
}
export function doSomeWork() {
using file = new TempFile(".some_temp_file");
// use file...
if (someCondition()) {
// do some more work...
return;
}
} // スコープの最後に `Symbol.dispose` が呼ばれる
using
はフロントエンド開発ではあまり使わないかもしれませんが、実はテストコードを書くときに便利かもしれません。
const mockSomething = () => {
// モックコード...
return {
[Symbol.dispose]: () => {
// モックのテアダウン処理
}
}
}
it('should foo', () => {
using mock = mockSomething();
// スコープの最後に自動的にモックのテアダウン処理が呼ばれる
});
そもそもusing
キーワードは ECMAScript Explicit Resource Management (proposal stage 3) のものなので、そろそろTypeScriptだけでなくJavaScriptでも使えるようになります。
const T
const T
は、定数型パラメータの一種です。
例えば、以下のようにジェネリック関数を定義すると
declare function useStatus<T>(statuses: T[]): T;
パラメーターの statuses
に string[]
を渡すと、関数の戻り値の型が string
になります。
const loadingStatus = useStatus(['loading', 'idle']);
// loadingStatus: string
しかし、const T
で定義すると関数の戻り値の型がもっと具体的に推論されます。
declare function useStatus<const T>(statuses: T[]): T;
const loadingStatus = useStatus(['loading', 'idle']);
// loadingStatus: 'loading' | 'idle'
以前は同じことをするために、パラメータを渡す際に as const
を付ける必要がありましたが、const T
で定義すれば使用する側が使いやすくなります!
Awaited
Awaited
は Utility Types の一つで、Promiseが解決する型を抽出するために使用されます。
type ExampleType = Promise<string>;
type ResolvedType = Awaited<ExampleType>; // ResolvedTypeはstring
ネストされたPromiseでも抽出することが可能です。
type NestedPromise = Promise<Promise<number>>;
type ResolvedNestedType = Awaited<NestedPromise>; // ResolvedNestedTypeはnumber
非Promise型で使用すると、Awaitedはその型自体を返します。
type NonPromiseType = string;
type ResolvedNonPromiseType = Awaited<NonPromiseType>; // ResolvedNonPromiseTypeはstring
React開発におけるAwaited
ユーティリティ型の実用例として、非同期fetchデータをuseStateに型定義する際に Await<ReturnType<typeof foo>>
の組み合わせで使えます。
async function fetchUserData(): Promise<{ name: string; age: number }> {
// Simulate an API call
return { name: 'John Doe', age: 30 };
}
function useUserData() {
const [data, setData] = useState<Awaited<ReturnType<typeof fetchUserData>> | null>(null);
useEffect(() => {
async function loadData() {
const userData = await fetchUserData();
setData(userData);
}
loadData();
}, []);
return data;
}
終わりに
まだ他にもたくさんあるので、Part 2に続けます(この記事が❤️をいっぱいもらえれば🙏)
Discussion