0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TypeScript 基本構文 忘備録

Posted at

目次

1. 概要
2. 想定読者
3. 型について
4. インターフェース
5. 関数
6. クラス
7. ジェネリック

【1. 概要】

TypeScriptをこれから触ってみる方向けに、どんな機能があるのかを簡単にまとめてみました。

【2. 想定読者】

・JavaScriptの経験がある方。
・TypeScriptってそもそも何ぞや、の基本は抑えておられる方。

【3. 型について】

image.png

プリミティブ型

boolean
const b: boolean = true;
number
const n: number = 0;
string
const s: string = "string";
enum
enum Employee {
    FirstName,
    LastName,
    Age
}

const employeeFirstName: Employee = Employee.FirstName
console.log(employeeFirstName);
// output: 0

console.log(Employee[employeeFirstName]);
// output: FirstNam
any
let randomValue: any = 10;
randomValue = 'Mateo';   // OK
randomValue = true;      // OK

型アサーション

(randomValue as string).toUpperCase();のようにas構文で「信頼してください、わかってやっています」ということをコンパイラに伝える。

型アサーション
let randomValue: unknown = 10;

randomValue = true;
randomValue = 'Mateo';

// このまま下記コードを実行すると、'randomValue' is of type 'unknown'.とエラーが出る。
// randomValue.toUpperCase();

if (typeof randomValue === "string") {
    console.log((randomValue as string).toUpperCase());    //* Returns MATEO to the console.
} else {
    console.log("Error - A string was expected here.");    //* Returns an error message.
}

共用体型

パイプ (|) を使用して、代入できる値の型を制限する。

共用体型
let multiType: number | boolean;
multiType = 20;         // OK
multiType = true;       // OK
multiType = "twenty";   // ERROR

型ガード

型ガードとは、ある値に対して特定の型かどうかをチェックし、その結果に応じて処理を分けることを指す。

型ガード
function add(x: number | string, y: number | string) {
    if (typeof x === 'number' && typeof y === 'number') {
        return x + y;
    }
    if (typeof x === 'string' && typeof y === 'string') {
        return x.concat(y);
    }
    throw new Error('Parameters must be numbers or strings');
}

console.log(add('one', 'two'));  //* Returns "onetwo"
console.log(add(1, 2));          //* Returns 3
console.log(add('one', 2));      //* Returns error

交差型

次の例では、Employee と Manager という 2 つのインターフェイスを定義した後、両方のインターフェイスのプロパティを併せ持つ ManagementEmployee という新しい交差型を作成する。

交差型
interface Employee {
  employeeID: number;
  age: number;
}
interface Manager {
  stockPlan: boolean;
}
type ManagementEmployee = Employee & Manager;
let newManager: ManagementEmployee = {
    employeeID: 12345,
    age: 34,
    stockPlan: true
};

リテラル型の定義

変数に代入できる値を制限する。
stringnumberbooleanの3つで使用可能。

リテラル型の定義
type testResult = "pass" | "fail" | "incomplete";
let myResult: testResult;
myResult = "incomplete";    // OK
myResult = "pass";          // OK
myResult = "failure";       // ERROR

配列

下記の2通りの定義が可能。

配列
let list1: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3];

【4.インターフェース】

TypeScript のコーディングのガイドラインでは、インターフェイスを文字Iで始めないことを勧めています。

インターフェース
interface Employee {
    firstName: string;
    lastName: string;
    age?: number;
    fullName(): string;
}

// Employeeインターフェースの拡張
interface Manager extends Employee {
    phoneNumber: number;
}

let employee: Manager = {
    firstName : "Emil",
    lastName: "Andersson",
    phoneNumber: 12345678901,
    fullName(): string {
        return this.firstName + " " + this.lastName;
    }
}

employee.firstName = 10;  //* Error - Type 'number' is not assignable to type 'string'
プロパティの種類
必須 firstName: string;
省略可能 firstName?: string;
読取専用 readonly firstName: string;

インターフェイスを使用してJavaScript APIを記述

const fetchURL = 'https://jsonplaceholder.typicode.com/posts'

interface Post {
    userId: number;
    id: number;
    title: string;
    body: string;
}

async function fetchPosts(url: string) {
    let response = await fetch(url);
    let body = await response.json();
    return body as Post[];
}

async function showPost() {
    let posts = await fetchPosts(fetchURL);
    let post = posts[0];
    console.log('Post #' + post.id)
    console.log('Author: ' + (post.userId === 1 ? "Administrator" : post.userId.toString()))
    console.log('Title: ' + post.title)
    console.log('Body: ' + post.body)
}

showPost();

【5. 関数】

名前付き関数

名前付き関数
// 戻り値あり
function addNumbers1 (x: number, y: number): number {
   return x + y;
}
addNumbers(1, 2);

// 戻り値なし
function addNumbers2 (x: number, y: number): void {
   console.log(x + y);
}

匿名関数

匿名関数
let addNumbers = function (x: number, y: number): number {
   return x + y;
}
addNumbers(1, 2);

アロー関数

アロー関数
// 匿名関数
let addNumbers1 = function (x: number, y: number): number {
   return x + y;
}

// アロー関数(単一行ver)
let addNumbers2 = (x: number, y: number): number => x + y;

// アロー関数(複数行ver)
let total2 = (input: number[]): number => {
    let total: number =  0;
    for(let i = 0; i < input.length; i++) {
        if(isNaN(input[i])) {
            continue;
        }
        total += Number(input[i]);
    }
    return total;
}

パラメーターの種類

省略可能パラメーター
function addNumbers (x: number, y?: number): number {
    if (y === undefined) {
        return x;
    } else {
        return x + y;
    }
}

addNumbers(1, 2); // Returns 3
addNumbers(1);    // Returns 1
規定値を指定したパラメーター
function addNumbers (x: number, y = 25): number {
   return x + y;
}

addNumbers(1, 2);  // Returns 3
addNumbers(1);     // Returns 26
restパラメーター
// 複数のパラメーターを 1 つのグループとして扱う
let addAllNumbers = (firstNumber: number, ...restOfNumbers: number[]): number => {
   let total: number =  firstNumber;
   for(let counter = 0; counter < restOfNumbers.length; counter++) {
      if(isNaN(restOfNumbers[counter])){
         continue;
      }
      total += Number(restOfNumbers[counter]);
   }
   return total;
}

addAllNumbers(1, 2, 3, 4, 5, 6, 7);  // returns 28
addAllNumbers(2);                    // returns 2
addAllNumbers(2, 3, "three");        // flags error due to data type at design time, returns 5
分解オブジェクトパラメーター
interface Message {
   text: string;
   sender: string;
}

function displayMessage({text, sender}: Message) {
    console.log(`Message from ${sender}: ${text}`);
}

displayMessage({sender: 'Christopher', text: 'hello, world'});

関数型

関数型
// 関数型を定義
type calculator = (x: number, y: number) => number;

// インターフェースの場合は、下記のように定義
interface Calculator {
    (x: number, y: number): number;
}

// 関数型を使用し、関数を定義
let addNumbers: calculator = (x: number, y: number): number => x + y;
let subtractNumbers: calculator = (x: number, y: number): number => x - y;

// 戻り値に関数型を指定
let doCalculation = (operation: 'add' | 'subtract'): calculator => {
    if (operation === 'add') {
        return addNumbers;
    } else {
        return subtractNumbers;
    }
}

let calculationFunction = doCalculation('add');
calculationFunction(1,2); // return 3

【6. クラス】

アクセス修飾子

アクセス修飾子 説明
public アクセス修飾子を指定しない場合、既定値はpublicです。publicキーワードを使用して、メンバーを明示的にpublicに設定することもできます。
private privateキーワードを使用してメンバーを変更すると、そのメンバーを含むクラスの外部からはアクセスできなくなります。
protected protected修飾子はprivate修飾子とほとんど同じように機能しますが、protectedと宣言されたメンバーには、派生クラス内でもアクセスできる点が異なります。
readonly readonly修飾子を使用して、プロパティを readonly にすることができます。readonlyプロパティは、宣言時またはconstructorで初期化されるときにのみ設定できます。
クラス
// インターフェース
interface Vehicle {
   // pubclicメンバーのみ宣言可能
   doors: number;
   accelerate(speed: number): void;
}

// Carクラス
class Car implements Vehicle {
   // プロパティ
   private static numberOfCars: number = 0; // staticプロパティ
   private _doors: number;

   // コンストラクタ
   constructor(doors = 4) {
       Car.numberOfCars++;

       if ((doors % 2) === 0) {
           this._doors = doors;
       } else {
           throw new Error('Doors must be an even number');
       }
   }

   // アクセサー
   get doors() {
       return this._doors;
   }
   set doors(doors) {
       if ((doors % 2) === 0) {
           this._doors = doors;
       } else {
           throw new Error('Doors must be an even number');
       }
   }

   // メソッド
   static getNumberOfCars(): number {
       return Car.numberOfCars;
   }
   accelerate(speed: number): void {
       this.showDoor()
       console.log('run accelerate.')
   }
   // サブクラスからもアクセスするため「protected」を使用
   protected showDoor(): void {
       console.log(`ドア数は${this.doors}です。`);
   }
}

// Carクラスを継承したElectricCarクラス
class ElectricCar extends Car {
   // Properties unique to ElectricCar
   private _range: number;

   // Constructor
   constructor(range: number, doors = 2) {
       super(doors); // スーパークラスのconstructorを実行
       this._range = range;
   }

   // Accessors
   get range() {
       return this._range;
   }
   set range(range) {
       this._range = range;
   }

   // Methods
   charge() {
       console.log(this.showDoor() + " is charging.")
   }
   // オーバーライド
   accelerate(): void {
       console.log('run electricCar accelerate.');
   }
}

【7. ジェネリック】

image.png

ジェネリック
function getArray<T>(items : T[]) : T[] {
   return new Array<T>().concat(items);
}
let numberArray: number[] = getArray<number>([5, 10, 15, 20]);
numberArray.push(25);       // OK
numberArray.push('test');   // ERROR

// 複数個
function identity<T, U> (value: T, message: U) : T {
   console.log(message);
   return value
}
let returnNumber = identity<number, string>(100, 'Hello!');
ジェネリック制約
type ValidTypes = string | number;

function identity<T extends ValidTypes, U> (value: T, message: U) {   // Return type is inferred
    let result: ValidTypes = '';
    let typeValue: string = typeof value;

    if (typeof value === 'number') {           // Is it a number?
        result = value + value;                // OK
    } else if (typeof value === 'string') {    // Is it a string?
        result = value + value;                // OK
    }

    console.log(`The message is ${message} and the function returns a ${typeValue} value of ${result}`);

    return result
}

let numberValue = identity<number, string>(100, 'Hello');
let stringValue = identity<string, string>('100', 'Hello');

console.log(numberValue);       // Returns 200
console.log(stringValue);       // Returns 100100
keyof
function getPets<T, K extends keyof T>(pet: T, key: K) {
  return pet[key];
}

let pets = { cats: 4, dogs: 3, parrots: 1, fish: 6 };

console.log(getPets(pets, "fish")); // Returns 6
console.log(getPets(pets, 1));      // ERROR

ジェネリック インターフェイス

ジェネリック インターフェイス
interface Identity<T, U> {
    value: T;
    message: U;
}

let returnNumber: Identity<number, string> = {
    value: 25,
    message: 'Hello!'
}
ジェネリックインターフェースを関数型として宣言
interface ProcessIdentity<T, U> {
    (value: T, message: U): T;
}

function processIdentity<T, U> (value: T, message: U) : T {
    console.log(message);
    return value
}

let processor: ProcessIdentity<number, string> = processIdentity;
let returnNumber1 = processor(100, 'Hello!');   // OK
let returnString1 = processor('Hello!', 100);   // Type check error
ジェネリックインターフェースをクラス型として宣言
interface ProcessIdentity<T, U> {
    value: T;
    message: U;
    process(): T;
}

class processIdentity<X, Y> implements ProcessIdentity<X, Y> {
    value: X;
    message: Y;
    constructor(val: X, msg: Y) {
        this.value = val;
        this.message = msg;
    }
    process() : X {
        console.log(this.message);
        return this.value
    }
}

let processor = new processIdentity<number, string>(100, 'Hello');
processor.process();           // Displays 'Hello'
processor.value = '100';       // Type check error

ジェネリッククラス

class processIdentity<T, U> {
    private _value: T;
    private _message: U;
    constructor(value: T, message: U) {
        this._value = value;
        this._message = message;
    }
    getIdentity() : T {
        console.log(this._message);
        return this._value
    }
}
let processor = new processIdentity<number, string>(100, 'Hello');
processor.getIdentity();      // Displays 'Hello'

カスタムの型とクラスでジェネリックを実装

class Car {
    make: string = 'Generic Car';
    doors: number = 4;
}
class ElectricCar extends Car {
    make = 'Electric Car';
    doors = 4
}
class Truck extends Car {
    make = 'Truck';
    doors = 2
}
function accelerate<T extends Car> (car: T): T {
    console.log(`All ${car.doors} doors are closed.`);
    console.log(`The ${car.make} is now accelerating!`)
    return car
}

let myElectricCar = new ElectricCar;
accelerate<ElectricCar>(myElectricCar);
let myTruck = new Truck;
accelerate<Truck>(myTruck);

// 出力
// "All 4 doors are closed."
// "The Electric Car is now accelerating!"
// "All 2 doors are closed."
// "The Truck is now accelerating!"
0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?