インターセクション型
・合併型(uniontypes):AかBどちらかの型を持つ どちらかの型が成立すればOK・交差型(intersection):AとB両方の型を持つ(共通する型ではない)
両方の型を満たせばOK
type Engineer = {
name: string;
role: string;
};
type Blogger = {
name: string;
follower: number;
};
type EandB = Engineer & Blogger;
const suda: EandB = {
name: "masaki",
role: "front-end",
follower: 10000,
};
Union 型の絞り込み
interface Hoge {
foo: string;
bar: number;
}
interface Piyo {
foo: number;
baz: boolean;
}
type HogePiyo = Hoge | Piyo;
//オブジェクトにbarとbaz両方あるとどちらの型になるのかわからないので、参照できない
const obj: HogePiyo = {
foo: 'hello',
bar: 0,
baz:false
};
//プロパティ 'bar' は型 'HogePiyo' に存在しません。
//プロパティ 'bar' は型 'Piyo' に存在しません。
const aaa = obj.bar
in
'bar' in objというのはbarというプロパティがobjに存在するならtrueを返し、そうでないならfalseを返す式 型を絞り込めば、正しく使える
function useHogePiyo(obj: Hoge | Piyo): void {
// ここではobjはHoge | Piyo型
if ('bar' in obj) {
// barプロパティがあるのはHoge型なのでここではobjはHoge型
console.log('Hoge', obj.bar);
} else {
// barプロパティがないのでここではobjはPiyo型
console.log('Piyo', obj.baz);
}
}
Type guard
typeof演算子は与えられた値の型を文字列で返す演算子
function func(value: string | number): number {
if ('string' === typeof value) {
// valueはstring型なのでlengthプロパティを見ることができる
return value.length;
} else {
// valueはnumber型
return value;
}
}
instanceof
class Dog {
speak() {
console.log("bow-bow");
}
}
class Bird {
speak() {
console.log("tweet-tweet");
}
fly() {
console.log("flutter");
}
}
type Pet = Dog | Bird;
function havePet(pet: Pet) {
pet.speak();
if (pet instanceof Bird) {
pet.fly();
}
}
havePet(new Bird());
//コンソール
tweet-tweet
flutter
havePet(new Dog());
//コンソール
bow-bow
タグ付きユニオン
オブジェクトに対してユニオン型を使うときに役立つ//type: 'Some'
//type: 'None'
//というタグをつけておく
//このタグを使って、型を分ける
interface Some<T> {
type: 'Some';
value: T;
}
interface None {
type: 'None';
}
type Option<T> = Some<T> | None;
//ifまたはswitchで場合分け
function map<T, U>(obj: Option<T>, f: (obj: T)=> U): Option<U> {
if (obj.type === 'Some') {
// ここではobjはSome<T>型
return {
type: 'Some',
value: f(obj.value),
};
} else {
return {
type: 'None',
};
}
}
//上と下は同じ
function map<T, U>(obj: Option<T>, f: (obj: T)=> U): Option<U> {
switch (obj.type) {
case 'Some':
return {
type: 'Some',
value: f(obj.value),
};
case 'None':
return {
type: 'None',
};
}
}
ユニオン型とインターセクション型を合わせて使ってみる
interface Hoge {
type: 'hoge';
foo: string;
}
interface Piyo {
type: 'piyo';
bar: number;
}
interface Fuga {
baz: boolean;
}
type Obj = (Hoge | Piyo) & Fuga;
function func(obj: Obj) {
// objはFugaなのでbazを参照可能
console.log(obj.baz);
if (obj.type === 'hoge') {
// ここではobjは Hoge & Fuga
console.log(obj.foo);
} else {
// ここではobjはPiyo & Fuga
console.log(obj.bar);
}
}
型アサーション
手動で型を上書きする as//今の状態の型
//const input: HTMLElement | null
const input = document.getElementById('input')
//input.valueなど使えない
const input = <HTMLInputElement>document.getElementById('input')
//または
const input = document.getElementById('input') as HTMLInputElement
input.value = 'value'
!
nullじゃないと言い切る方法 if文で条件分岐しなくてもよくなる//今の状態の型
//const input: HTMLElement
const input = document.getElementById('input')!
インデックスシグニチャ
・オブジェクトが複数のプロパティを持つ可能性を示す ・[key:T]:U のように示す ・keyはstringかnumberのみconst capitals: {
[countryName:string]:string
} = {
japan: 'tokyo',
korea: 'soul',
//エラー
age:23
}
関数のオーバーロード
戻り値の型を正しく伝えるfunction toUpperCase(x: string | number): string | number {
if (typeof x === "string") {
return x.toUpperCase();
}
return x;
}
const upperHello = toUpperCase("hello")
//upperHelloの型は、const upperHello: string | number
//---------------------------------------------------
function toUpperCase(x: string ): string
function toUpperCase(x: number): number
function toUpperCase(x: string | number): string | number {
if (typeof x === "string") {
return x.toUpperCase();
}
return x;
}
//オーバーロードすることによって関数の戻り値の型を正しくできる
const upperHello = toUpperCase("hello")
Optional Chaining
プロパティが連結していくとき指定したプロパティがなければnullを返す//?はあってもなくてもいいプロパティ
interface DownLoadedData {
id: number;
user?: {
name?: {
first: string;
last: string
}
}
}
const downloadedData: DownLoadedData = {
id:1
}
//エラー
//オブジェクトは 'undefined' である可能性があります
console.log(downloadedData.user.name)
//解決策の一つ
//userがあったらnameを返す
//なければundefinedを返す
console.log(downloadedData.user?.name)
Nullish Coalescing
userがundefined or nullの場合??の後ろを返すconst userData = downloadedData.user ?? 'no-user'
LookUp型
オブジェクトの型のメンバが持っている型にアクセスするinterface DownLoadedData {
id: number;
user: {
name?: {
first: string;
last: string;
};
};
}
type id_1 = DownLoadedData['id']
//number
type id_2 = DownLoadedData['user']['name']
//type id_2 = {
// first: string;
// last: string;
//} | undefined
具体例
第一引数Tは{ foo: string; bar: number; }型
第二引数K extends keyof Tはfooまたはbarに限定する
戻り値T[K]は({ foo: string; bar: number; })['foo']型つまりstring
function pick<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const obj = {
foo: 'string',
bar: 123,
};
const str: string = pick(obj, 'foo');
const num: number = pick(obj, 'bar');
// エラー: Argument of type '"baz"' is not assignable to parameter of type '"foo" | "bar"'.
pick(obj, 'baz');
constアサーション
as const をつけると変えられなくなるlet milk = 'milk' as const
//let milk: "milk"
const array = [10,20]
//const array: number[]
const array = [10,20] as const
//const array = [10,20] as const