基本の型指定
基本
Number: 数値
String: 文字
Boolean: true / false
Any: 全ての型
Void: 返り値がない
undefined: undefined
null: null
配列
let list: number[] = [1, 2, 3];
Tuple型
// 0番目にnumber、1番目にstringのみ入れることができる
let tuple: [string, number] = ["myname", 3];
Enum形
デフォルト値なし
// 型の定義
enum Family {Rick, Mike,Json};
// 使用するとインデックス番号が入る
let Rick:number = Family.Rick; // 0
let Mike:number = Family.Rick; // 1
let Json:number = Family.Rick; // 2
デフォルト値あり
// 型の定義
enum Ages {Rick = 21 , Mike = 22 , Json = 23};
// 使用するとデフォルト値が入る
let Rick:number = Family.Rick; // 21
let Mike:number = Family.Rick; // 22
let Json:number = Family.Rick; // 23
文字列はエラー
// エラー
enum Hello {Rick = "Rick dayo" , Mike = "Mike dayo" , Json = 'Json dayo'};
インデックスを指定してキーを取り出す
// 型の定義
enum Ages {Rick = 21 , Mike = 22 , Json = 23};
let Rick:string = Family[21]; // Rick
let Mike:string = Family[22]; // Mike
let Json:string = Family[23]; // Json
Never型
・returnが絶対に走らない場合、戻り値がない場合never型になる
・値は入れられない
// errorを返す関数
const error = ():never => {
throw new Error("エラー");
}
関数
functionキーワードによる関数定義
function bmi(height: number, weight: number):number {
return weight / (height * height);
}
無名関数による関数定義
let bmi = function (height:number, weight:number):number {
return weight / (height * height);
}
Restパラメータを設定する
const sum = (...values: number[]):number => {
console.log(values); // [0,1,2,3,4]
return 100;
}
sum(1,2,3,4);
// reduceを使う
const reducer = (accumulator: number, currentValue: number):number => {
console.log({accumulator, currentValue});
return accumulator + currentValue;
}
[1,2,3,4].reduce(reducer);
// {accumulator:1, currentValue:2}
// {accumulator:3, currentValue:3}
// {accumulator:6, currentValue:4}
voidとneverの違い
Void型
・戻り値undefinedを含む
・returnを省略したり、戻り値のないreturnをするとundefinedが返る
Never型
・neverはそもそもreturnをしない。
・例外を投げる場合や無限ループをする場合など、戻り値が得られないときに使う
・undefinedも受け付けないので、戻り値の型にneverを指定した場合はreturnは書けない。
onst void1 = () => {}
const void2 = () => { return }
const never = () => { while(true){} }
let voidFunc1:never = void1() // エラー
let voidFunc2:never = void2() // エラー
let neverFunc:never = never() // OK
Object型
・プリミティブ型ではないことを表現する型
// プリミティブ型を引数にとらないようにする関数
function viewObject(o: object): void {
console.log(`myData: ${o}`);
};
インターフェース
オブジェクトが特定の構造が合っているかどうかチェックする。
interface Props {
name: string;
}
function getMyname(props:Props): string {
return `I'm ${props.name}`;
}
オーバーロード
シグネチャ = 関数の実態は書かずに、引数戻り値などの型を設定したもの
function double(value:number):number {
return value * 2;
}
function double(value:string):string {
return value + value;
}
// 被っているのでエラーとなる。 この場合、シグネチャを使う
↓
// シグネチャの宣言
function double(value:number):number;
function double(value:string):string;
function double(value: any): any { // 型制約はシグネチャで定義して、関数の実態では全ての型を受け取れるようにする
if(typeof value === "number") {
return value * 2;
} else {
return value + value;
}
}
クラス
class Person {
name: string;
age: number;
constructor(name: string, age: number) { // constructorもメソッド(関数)なので引数が必要
this.name = name;
this.age = age;
}
profile(): string {
return `name; ${this.name}, age: ${this.age}`
}
}
let taro = new Person("taro", 30);
console.log(taro);
アクセス修飾子
class Person {
public name: string; // インスタンスからアクセスできる
private age: number; // インスタンスからはアクセスできない
protected nationality: string; // 子クラス(サブクラス)からもアクセスができる
constructor(name: string, age: number, nationality: string) { // constructorもメソッド(関数)なので引数が必要
this.name = name;
this.age = age;
this.nationality = nationality;
}
profile(): string {
return `name; ${this.name}, age: ${this.age}`;
}
}
class Android extends Person { // Personクラスを継承
constructor(name: string, age: number, nationality: string) {
super(name, age, nationality); // 親クラスのconstructorを使う
}
profile(): string {
// エラー: ageはprivateなので、小クラスで使えない
return `name; ${this.name}, age: ${this.age}, nationality: ${this.nationality}`;
}
}
let taro = new Person("taro", 30, "Japan");
console.log(taro.name); // アクセスできる
console.log(taro.age); // アクセスできない
constructor
アクセス修飾子にconstructorに記載すると、初期化処理がされる
class Person {
constructor(public name: string, protected age: number) {}
}
const me = new Person("Ogura", 100);
console.log(me); // {name; "Ogura", age: 100}
getterとsetter
class MyNumberCard {
private _owner: string; // メンバ変数がget ownerと名前が被るので、アンダーバーをつける
private _secretNumber: number;
constructor(owwner: string, secretNumber: number) {
this._owner = owner;
this._secretNumber = secretNumber;
}
get owner() {
return this._owner;
}
set secretNumber(secretNumber: number) {
thIs._secretNumber = secretNumber;
}
debugPrint() { // 変更を確認するメソッド
return `secretNumber: ${this._secretNumber}`;
}
}
readonly修飾子
class VisaCard {
readonly owner: string;
constructor(owner: string) {
this.owner = owner;
}
}
let myVisaCard = new VisaCard("Rick");
console.log(myVisaCard.owner); // Rick
myVisaCard.owner = "Eddie"; // readonlyなのでエラー
省略した書き方もできる
class VisaCard {
constructor(public readonly owner: string) {}
}
readonlyの場合、アクセスできることが前提なので、さらにpublicを省略できる
class VisaCard {
constructor(readonly owner: string) {}
}
namespaceによる名前空間
複数のPersonクラスを定義するために、namespaceに閉じ込める
namespace Japanese {
export class Person { // exportがないとJapanese.Personとしてもアクセスできない
constructor(public name:string){}
}
}
namespace English {
export class Person {
constructor(
public firstName:string,
public middleName:string,
public lastName:string
){}
}
}
const me = new Japanese.Person("Gura");
console.log(me.name); // Gura
const michel = new English.Person("Michel", "Mike", "Jhonson");
ネストする場合
namespace Japanese {
export namespace Tokyo {
export class Person {
constructor(public name:string){}
}
}
export namespace Osaka {
export class Person {
constructor(public name:string){}
}
}
}
const me = new Japanese.Tokyo.Person("Gura");
const meOsaka = new Japanese.Osaka.Person("Guraやで");
継承
基本
class Animal {
run(): string {
return "I can run";
}
}
class Lion extends Animal {
run(): string {
return "I can run 80km.";
}
}
let animal = new Animal();
console.log(animal.run()); // I can run
let lion = new Lion();
console.log(lion.run()); // I can run 80km.
Constructorを追加
class Animal {
constructor(public name: string) {}
run(): string {
return "I can run";
}
}
class Lion extends Animal {
public speed: number;
constructor(name: string, speed: number) {
super(name);
this.speed = speed;
}
run(): string {
return `${super.run()} ${this.speed}km.`; // 親クラスのメソッドrunを呼び出す
}
}
console.log(new Animal("Mickey").run()); // I can run
console.log(new Lion("Simba", 80).run()); // I can run 80km.
抽象クラスと抽象メソッド
abstract class Animal {
abstract cry(): string;
}
class Lion extends Animal {
cry() {
return "roar";
}
}
インターフェースで二つの親クラスを継承する
ダメなパターン
class Sword {}
class Momo {}
class Momotaro extends Sword, Momo {} // エラー:親クラスを2つ継承できない
interfaceとimplementsを使う
interface Momo {
bougyo(): void;
}
interface Sword {
kougeki(): void;
}
class Momotaro implements Momo, Sword {
bougyo(): void {
console.log("mamoruyo");
}
kougeki(): void {
console.log("atetayo");
}
}
const momotaro = new Momotaro();
momotaro.bougyo();
momotaro.kougeki();
高度な型
ジェネリクス
関数
const echo = <T>(arg: T): T => {
return arg;
}
console.log(echo<number>(100));
クラス
class Mirror<T> {
constructor(public value : T) {}
echo(): T {
return this.value;
}
}
console.log(new Mirror<number>(123).echo());
型アサーション (型を示す)
let length = name.length as number;
別パターン1
let length = (name as string).length; // 変数lengthの型はnumber
別パターン2 (非推奨)
let length = (<string>name).length; // 変数lengthの型はnumber
constアサーション (型の書き替えを行えない)
変数
let nickname = "Gura" as const; // nickname: "Gura"型
nickname = "Ogura"; // エラー: "Ogura型に変更できない
オブジェクト
let profile = {
name: "Atshushi", // readonly name
height: 178 // readonly height
} as const;
profile.name = "Ash"; // エラー: as constのおかげでreadonly型になっている
インデックスシグネチャ
ダメな例
nameプロパティは追加できても、ageを追加したらまたエラーが出る
let profile: {name?: string} = {};
profile.name = "Gura";
profile.age = 43; // Error
インデックスシグネチャを使う
let profile: { [index: string]:string | number } = {};
profile.name = "Gura";
profile.age = 43;
Utillity Types / Conditional Types
全てをオプショナル、またはRequiredにするUtillity Types
type Profile = {
name: string;
age: number;
}
// 型引数にProfileを渡す
type PartialType = Partial<Profile>; // 全てオプショナル に
type RequiredType = Required<Profile>; // 全て必須 に
keyof と in、Mapped Types
keyof
type Profile = {
name: string;
age: number;
}
type PropertyTypes = keyof Profile; // PropartyTypes = "name" | "age";
keyof と inを使い、Partialに似た独自のUtillity Typesを作る(Mapped Types)
type Optional<T> = {
[P in keyof T]?: T[P] | null; // inを使い1個ずつ取り出す、Pは"name"または"age"になる
}
type Optional Profile = Optional<Profile>;
Readonly
type Profile = {
name: string;
age: number;
}
type PersonalDataType = Readonly<Profile>;
const friend:PersonalDataType = {
name: "Shigeru",
age: 40,
}
friend.age++; // エラー: Readonlyなのでインクリメントできない
Record
type Prefectures = "Tokyo" | "Kyoto" | "Osaka" | "Nagoya";
type NinjaInfo = {
kanji_name: string;
number_of_people: number;
}
const ninjaInJapan: Record<Prefectures, NinjaInfo> = {
Tokyo: { kanji_name: "東京", number_of_people: 1960 },
Kyoto: { kanji_name: "京都", number_of_people: 249 },
Osaka: { kanji_name: "大阪", number_of_people: 2 },
Nagoya: { kanji_name: "名古屋", number_of_people: true }, // エラーがちゃんと出る
}
不要な型を排除する(Exclude) / 特定の型を取り出す(Extract)
不要な型を排除する: Exclude<全体の型, 削除したい型>
type DebugType = () => void;
type SomeTypes = string | number | DebugType;
// Exclude
type FunctionType = Exclude<SomeTypes, string | number>; // type FunctionType = () => void;
type NunFunctionType = Exclude<SomeTypes, DebugTypes>; // NunFunctionType = string | number;
type TypeExcludingFunction = Exclude<SomeTypes, Function>; // TypeExcludingFunction = string | number;
特定の型を取り出す: Extract<全体の型, 取り出したい型>
type DebugType = () => void;
type SomeTypes = string | number | DebugType;
type FunctionTypeByExtract = Extract<SomeTypes, DebugType>; // FunctionTypeByExtract = () => void;
type NonFunctionTypeByExtract = Extract<SomeTypes, string | number>; // NonFunctionTypeByExtract = string | number;
type FunctionTypeExtractingFunction = Extract<SomeTypes, Function>; // FunctionTypeExtractingFunction = () => void
Nullやundefinedを排除する(NonNullable)
NonNullable
type NullableTypes = string | number | null | undefined;
type NonNullableTypes = NonNullable<NullableTypes>; // type NonNullableTypes = string | number;
必要なものだけ取り出して新たな型を作る(Pick)
type DetailedProfile = {
name: string;
height: number;
weight: number;
}
// Pick<参照する型, 取り出したい型 | 取り出したい型>
type SimpleProfile = Pick<DetailedProfile, "name" | "weight">; // type SimpleProfile = {name: string, weight: number;}
特定の型を除外して新たな型を作る(Omit)
type DetailedProfile = {
name: string;
height: number;
weight: number;
}
type SmallProfile = Omit<DetailedProfile, "height">; // type SmallProfile = {name: string, weight: number;}
関数の戻り値の型を取得する(ReturnType)
function add(a: number, b: number) {
return a + b;
}
type ReturnTypeFromAdd = ReturnType<typeof add>; // type ReturnTypeFromAdd = number;
関数が受け取る引数と同じ構造の型を作る(Parameters)
const debugProfile = (name: string, age: number) => {
console.log({ name, age });
}
debugProfile("Ham", 43);
type Profile = Parameters<typeof debugProfile>; // type Profile = [string, number];
const profile: Profile = ["Green", 21];
const profile: Profile = [32, "Mynames"]; // tuple型なのでエラー
constructorが受け取る引数と同じ構造の型を作る(ConstructorParameters)
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
let taro = new Person("Taro", 30);
type PersonType = typeof Person; // type PersonType = typeof Person;
type Profile = ConstructorParameters<PersonType>; // type Profile = [string, number];
const profile: Profile = ["Ham", 43];
const ham = new Person(...profile);