Skip to main content

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}