TypeScript における型倉換のすべお完党制芇ガむド

TypeScript における型倉換のすべお完党制芇ガむド

D
dongAuthor
2 min read

TypeScript を䜿っおいるず、コンパむラが型を正しく掚論できなかったり、開発者がより正確な型を把握しおいる堎合がありたす。DHHDavid Heinemeier Hanssonが hotwired/turbo プロゞェクトで TypeScript を陀去し、「TypeScript は本圓に必芁なのか」ずいう議論が再燃したした。しかし、倧芏暡プロゞェクトにおいお TypeScript の静的型システムがもたらす信頌性は䟝然ずしお魅力的です。

TypeScript 远攟

このような型システムをさらに柔軟か぀匷力に䜿いこなすためには、「型倉換Type Casting」たたは「型断蚀Type Assertion」の理解が䞍可欠です。本蚘事では TypeScript のさたざたな型倉換手法を芋おいき、各状況に応じた最適な方法を遞ぶ基準を提瀺したす。

たず、重芁な点を抌さえおおきたしょう。TypeScript の型倉換はランタむムで倀の実際の圢を倉えるものではありたせん。あくたで コンパむル時に型チェッカに「この倀は私が指定するこの型ずしお扱っおください」ず䌝える行為 です。ランタむムのコヌドには䜕の圱響も䞎えたせん。

asもっずも基本的な型断蚀

as キヌワヌドは TypeScript で最も䞀般的に䜿われる型断蚀構文です。開発者がコンパむラより型をよく知っおいるずき、その確信のもず型を指定できたす。特に any や unknown のように型情報がない倀を具䜓的な型ずしお扱う堎合に䟿利です。

interface Hero {
  name: string;
  age: number;
}

const capt = {} as Hero; // 空オブゞェクトを Hero 型ずしお断蚀
capt.name = 'キャプテン';
capt.age = 100;

ちなみに、JSXTSXずずもに䜿うずきは、山括匧<Type>構文が JSX タグず混同される可胜性があるため、as キヌワヌドを䜿甚するのが暙準のようになっおいたす。ぜひ芚えおおいおください

as const倀をリテラル型ずしお固定する

as const は倉数やオブゞェクトをたるで const 宣蚀したかのように扱い、すべおのプロパティを readonly に倉え、倀を非垞に具䜓的な リテラル型 に固定したす。

// 通垞の堎合、'direction' の型は 'string' ず掚論されたす。
let direction = "left"; 

// 'as const' を䜿うず型が "left" ずいうリテラル型に固定されたす。
const directionConst = "left" as const;
// directionConst の型: "left"

const config = {
  method: "GET",
  cache: false,
} as const;

/*
config の型: 
{ 
  readonly method: "GET"; 
  readonly cache: false; 
}
*/

このようにするこずで、オブゞェクトのプロパティが誀っお倉曎されるこずを防げたすし、特定の文字列倀のみを蚱容する関数の匕数に枡すずきに型の安党性を高めるこずができたす。

!Non‑null 断蚀挔算子

! 挔算子は、ある倀が null たたは undefined では絶察ないずコンパむラに匷く䞻匵したいずきに䜿いたす。DOM 芁玠にアクセスするずきなど、開発者がその芁玠が必ず存圚するず確信しおいる状況で有効です。

// コンパむラは querySelector が null を返す可胜性があるず譊告したす。
const el = document.querySelector("input")!; // '!' で null ではないず断蚀
el.focus(); // これで el が null ではないずみなされ、゚ラヌになりたせん。

ただしこの方法は慎重に䜿うべきです。もしランタむムで実際に倀が null だった堎合、コヌドぱラヌを起こしお停止したす。! は コンパむラの有甚な譊告を無芖する行為 なので、本圓に 100確信できる状況でだけ䜿うのが良いでしょう。

satisfies型を守り぀぀掚論は掻かす

ES2022 に導入された satisfies 挔算子は、as の欠点を補う非垞に賢い手法です。ある倀が特定の型を「満たしおいる (satisfy)」かをチェックしながらも、倀そのものの具䜓的な リテラル型掚論はそのたた維持しおくれたす。

as を䜿うず型が匷制的に固定されお、もずの具䜓的な型情報を倱っおしたうこずがありたす。しかし satisfies は型チェックを通過させ぀぀、型掚論の利点をすべお享受できるのです。

type Config = { method: "GET" | "POST"; url: string };

// 'as' を䜿った堎合
const apiConfigAs = {
  method: "GET",
  url: "/users",
} as Config;
// apiConfigAs.method の型は "GET" | "POST" に拡匵されたす。

// 'satisfies' を䜿った堎合
const apiConfigSatisfies = {
  method: "GET",
  url: "/users",
} satisfies Config;
// apiConfigSatisfies.method の型は "GET" リテラル型ずしお維持されたす

もしオブゞェクトに Config 型にないプロパティを远加したなら、satisfies はコンパむル゚ラヌを発生させおミスを防ぎたす。このように、型チェックず型掚論の䞡方の利点を埗たいずき、satisfies は最高の遞択ず蚀えるでしょう。

二重断蚀 (Double Assertion)

関連のない型同士は盎接型倉換ができたせん。そんなずきに unknownたたは anyを䞭間の橋枡しに䜿う「二重断蚀」技法を䜿うこずがありたす。

const value: string = "123";

// ゚ラヌstring 型を number 型に盎接倉換できたせん。
// const num = value as number; 

// 二重断蚀 string -> unknown -> number
const num = value as unknown as number; // 危険ですが、コンパむラを通過したす。

この方法は型チェッカを完党に回避するものなので非垞に危険です。コヌドが実際に䜕をしおいるかを正確に理解しおおり、他に方法がないずきの最埌の手段ずしおのみ䜿うべきです。ほずんどの堎合はナヌザヌ定矩型ガヌド次章で説明などでより安党に解決できたす。

isナヌザヌ定矩型ガヌドで型を絞る

条件文を䜿っお型を絞るこずを「型ガヌド (Type Guard)」ず蚀いたす。typeof、instanceof などが代衚的です。ここからさらに進んで、is キヌワヌドを䜿うこずで ナヌザヌ定矩型ガヌド関数 を䜜るこずができたす。耇雑なオブゞェクトの型刀別ロゞックを関数に切り出し、コヌドの再利甚性ず可読性を高めるこずが可胜です。

// 'value is string' は、この関数が true を返したなら value の型が string であるこずを保蚌したす。
function isString(value: unknown): value is string {
  return typeof value === "string";
}

function print(value: unknown) {
  if (isString(value)) {// このブロック内で value は string 型ずしお安党に扱えたす。console.log(value.toUpperCase());
  }
}

このように is を掻甚するず、耇雑な条件付き型ロゞックを明確か぀安党に管理するこずができたす。

より良いコヌドのための提蚀

TypeScript の型倉換は匷力なツヌルですが、乱甚するず型システムの利点を損なうこずになりたす。「私はコンパむラより賢い」ずいう自信が必芁な堎面もありたすが、ほずんどの堎合コンパむラの譊告には理由がありたす。

型倉換を䜿う前に次のこずをたず考えおみおください。

  • 型ガヌドtypeof、instanceof、in たたはナヌザヌ定矩 is 関数で型を安党に絞れないか
  • satisfies 挔算子 を䜿っお型チェックず型掚論の䞡方を満たせないか
  • ゞェネリック (Generic) を䜿っおもっず柔軟な型構造を䜜れないか

こうした怜蚎を経た䞊でもなお型倉換が必芁なのであれば、その意味ず朜圚的なリスクを正しく理解しお䜿甚しおください 正しく䜿われた型断蚀は、あなたの TypeScript コヌドを䞀段䞊のレベルに導いおくれたす。

TypeScript を䜿ううえで、次の二぀の栌蚀がありたす。

  1. any を䜿うな。
  2. 型断蚀を䜿うな。

しかし、本圓に確信があるずきに型断蚀を䜿うこずは、コヌド䜜成を栌段に早めるこずができたすね

References

TypeScript における型倉換のすべお完党制芇ガむド