Typescript Nomial Type
#TypeScript
ID 型つくりたい
Nominal Typing - TypeScript Deep Dive 日本語版
リテラル
❌ { type, value } なのがやだ
Enums
as でつくるのがな〜
まあバリデーション付けて関数にすればいい
例えば
code:validate.ts
function FooId(id: String): FooId {
if (!validate(id)) throw new Error("invalid input");
return id as FooId
}
元の string にそのまま代入できる
❌ number で使えない
インタフェースの使用
⭕ TypeScript コンパイラチームでも使われている
Microsoft/TypeScript@7b48a18 - src/compiler/types.ts#L693-L698
as はまあ関数に閉じ込める
TypeScript による GraphQL バックエンド開発 - Speaker Deck p91
code:newtype.ts
declare const __newtype: unique symbol;
export type newtype<Constructor, Type> = Type & {
readonly __newtype: Constructor
}
export type TagId = newtype<'TagId', string>;
export function TagId(value: string): Result<TagId, ValidationError> {
return validate(value)
? ok(value as TagId)
: err(new ValidationError('IDの形式が不正です'))
}
// ---
export type FooId = newtype<'FooId', string>;
export type BarId = newtype<'BarId', string>;
export function FooId(value: string): FooId {
return value as FooId;
}
export function BarId(value: string): BarId {
return value as BarId;
}
let fooId = FooId('foo');
let barId = BarId('bar');
fooId = barId; // error
barId = fooId; // error
let str: string;
str = fooId;
str = barId;
unique symbol
TypeScript: Documentation - Symbols
Constructor で型ずらしてる
型変数であって Constructor 自体ではない、Id 型ごとに違う値をいれればよい、Name とかでもいい
__newtype の symbol が一意
使わないからといって never にすると FooId, TagId で型一致してしまう
Constructor だからといって typeof TagId なんかにすると同じ型のコンストラクタで型が揃っちゃう
ややテクいので
number 使わないなら Enum のほうが分かりやすい vs 1回定義したらいいの ラインの勝負かな