TypeScriptでは型を定義できます。これは大体Objectの絡んだプロパティを見る時が多く、そうでなくとも配列内部に何が入るか、のようなものがほとんどで、これが基本的な使い方です。
type UserType = {
id: number
name: string
memberType: number
}
type UsersType = Array<UserType>
しかし時折、プリミティブ値にもバリデーション的に型を用いたくなります。
JavaScript のデータ型とデータ構造 – JavaScript | MDN#プリミティブ値
上の例では memberType:string が問題になります。単に number では数値ならば何でもOKになってしまいます。これを防ぎます。
型とは違いますが、動きや構造が少しでも複雑ならば値を表現するクラスを作るのがわかりやすいです。ドメイン駆動設計におけるValueObjectの考え方です。
const MEMBER_TYPE_NORMAL = 1;
const MEMBER_TYPE_RED = 4;
const MEMBER_TYPE_BLUE = 5;
const MEMBER_TYPE_WHITE = 7;
const MEMBER_TYPES =[
MEMBER_TYPE_NORMAL,
MEMBER_TYPE_RED,
MEMBER_TYPE_BLUE,
MEMBER_TYPE_WHITE,
];
class MemberType{
readonly value: number
constructor(value: number) {
if (!MEMBER_TYPES.include(value)) {
throw new Error(`${value} は不正な値です`)
}
this.value = value
}
toString(): string {
return '' + this.value
}
}
type UserType = {
id: number
name: string
memberType: MemberType
}
type UsersType = Array<UserType>
こうすると memberType に不正な値を入れることはできなくなります。こうした時に少々面倒なのはクラスのインスタンス化処理の重さです。短い間隔のポーリングであったり、大量のデータを一度に受け取って加工するなどするとクラスを扱う処理の重さは案外問題になります(なりました)。TypeScriptは”自分には型があると思い込んでいるJavaScript”とも呼ばれるものでコンパイル後には処理をいくらか飛ばします。このため速度が問題になっているなどの時にはValueObjectでなくTypeScriptの型で特別な型を表現します。
const MEMBER_TYPE_NORMAL = 1;
const MEMBER_TYPE_RED = 4;
const MEMBER_TYPE_BLUE = 5;
const MEMBER_TYPE_WHITE = 7;
const MEMBER_TYPES:Array<number> =[
MEMBER_TYPE_NORMAL,
MEMBER_TYPE_RED,
MEMBER_TYPE_BLUE,
MEMBER_TYPE_WHITE,
];
// numberでありユニークな型MemberTypeを作る
// @see https://qiita.com/suin/items/ae9ed911ebab48c98835 公称型をTypeScriptで実現するための基礎
declare const memberTypeSymbol: unique symbol
type MemberType = number & { [memberTypeSymbol]: never }
// この関数で返すBooleanは MemberType であることを示すためのBooleanとTypeScriptに示す
const isMemberType = (value: number): value is MemberType => {
// MemberTypeであるために必須の条件を記述
if (!MEMBER_TYPES.includes(value)) {
throw new Error(`${value} はMemberTypeとして不正な値です`)
}
return true
}
type UserType = {
id: number
name: string
memberType: MemberType
}
type UsersType = Array<UserType>
このようにするとisMemberType関数を通すだけで済むようになります。
const currentMemberType = MEMBER_TYPE_WHITE;
function hoge(){
if(!isMemberType(currentMemberType)){
return;
}
const user: UserType = {
id: 1,
name: '太郎',
memberType: currentMemberType,
}
}