Typescript | and &
Typescriptの合併|
と公差&
がわかりにくかったので、食事の例で考えてみました。
献立表を作るとき、次のようにサラダとパスタとピザの型を定義します。
今回は、サラダとパスタのトマトは数を数えられるとしてnumber型、
ピザのトマトはペースト状なのでboolean型にしているので注意してください。
type Salad = {tomato: number}
type Pasta = {tomato: number, macaroni: boolean}
type Pizza = {tomato: boolean, cheeze: boolean}
REF
合併|について
各食事で必ずサラダをとり、ランチではパスタ、ディナーではピザを食べる
ときの、
サラダとPasta,Pizzaの合併|
を考えます。
type Lunch1 = Salad | Pasta
type Dinner1 = Salad | Pizza
合併は、いわゆる"または"の意味なので、どちらかの食事である必要があります。 ランチはPasta ⇒ Saladの関係なので、 少なくともtomatoがbooleanであればtrueとなり、 ディナーはPizzaとSaladは全く異なるので、SaladでもPizzaでもないとfalseとエラーになります。
const salad: Lunch1 = {tomato:0} //OK!
const pasta: Lunch1 = {tomato:0, macaroni:true} //OK!
const pizza: Dinner1 = {tomato:false, cheeze:true} //OK!
const _pizza: Dinner1 = {tomato:1 , cheeze:true} //ERROR!
//Object literal may only specify known properties, and 'cheeze' does not exist in type 'Salad'.
交差&について
ランチではパスタ、ディナーではピザを食べる食生活として、サラダとの交差&
を用いて定義します。
type Lunch2 = Salad & Pasta
type Dinner2 = Salad & Pizza
公差&
はかつという意味なのですが、Typescriptでは少しあつかいにくいので注意が必要です。
ランチではPasta ⇒ Saladの関係であり、必要条件であるパスタでないとfalseになるので、
SaladかつPastaだとマカロニサラダしか該当しなくなります。
ディナーに関しては、tomatoの型がSaladとPizzaで異なるので、
tomato:number&boolean)
=>tomato:never
になり, どんな料理でも合致しなくなります。
const salad2: Lunch2 = {tomato:0} //ERROR!
const pasta2: Lunch2 = {tomato:0, macaroni:true} //OK!
//Property 'macaroni' is missing in type '{ tomato: number; }' but required in type 'Pasta'.
const _pizza2: Dinner2 = {tomato:1 , cheeze:true} //ERROR!
const __pizza2: Dinner2 = {tomato:true, cheeze:true} //ERROR!
// Type 'number' is not assignable to type 'never'.
// Type 'true' is not assignable to type 'never'.
型のmergeについて
重複したkeyの型が異なるSaladとPizzaの型を合体させるには、条件とマップが必要となります。 Pizzaのkeyに対して、keyがSaladのkeyにあればSaladの型、出なければPizzaの型を返すことができます。 このとき、tomatoの型は、saladが優先されるのでnumber型になります。
type Salad = {tomato:number}
type Pizza = {tomato:boolean, cheeze:boolean}
type Dinner = {
[K in keyof Pizza]: K extends keyof Salad ? Salad[K] : Pizza[K]
} & Salad
const pizza: Dinner = {tomato:0 , cheeze:true} // OK !
const _pizza: Dinner = {tomato:false, cheeze:true} //Error !
// Type 'false' is not assignable to type 'number'.
// Dinner is {tomato:number, cheeze:boolean}