0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TypeScriptの仕様・パターン覚え書き

Last updated at Posted at 2021-09-25

基本の型指定

基本

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);
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?