[TypeScript] 型

### マップ型
stringのキーのマップ型

type stringArray = {
    [key in string]: string
}

const data1:stringArray = {
    'start': 'start',
    'middle': 'middle',
    'end': 'end'
}

data1['finish'] = '**end**'
data1[100] = 'ok'
console.log(data1)

enum

enum human {name='name', mail='mail'}

type HumanMap = {
    [key in human]: string
}

const taro:HumanMap = {
    name: 'taro',
    mail: 'taro@yamada'
}
console.log(taro)
const hana:HumanMap = {
    name: 'hanako',
    mail: 'hanak@gmail.com'
}
console.log(hana)

ユニオン型

class Student {
    name:string
    school:string
    grade:number

    constructor(nm:string, sc:string, gr:number){
        this.name = nm
        this.school = sc
        this.grade = gr
    }

    print():void{
        console.log('<< ' + this.name + ',' +
            this.school + ':' + this.grade + ' >>')
    }
}
class Employee {
    name: string
    title: string
    department:string

    constructor(nm:string, tt:string, dp:string){
        this.name = nm
        this.title = tt
        this.department =dp
    }

    print():void {
        console.log(this.name + '[' + this.title + 
            ',' + this.department + ']')
    }
}

type People = Student | Employee

const taro:People = new Student('taro', 'high school', 3)
const hana:People = new Employee('hanako', 'president', 'sales')
const sachi:People = new Student('schiko', 'jinir-high school', 1)
const jiro:People = new Employee('jiro', 'director', 'labo')

const data:People[] = [taro, hana, sachi, jiro]
for(let item of data){
    item.print()
}

ユニオン型を個別に処理

class Human {
    data: People[] = []

    add(item:People):void {
        this.data.push(item)
    }
    print():void {
        for(let item of this.data){
            let ob
            switch(item.constructor.name){
                case 'Student':
                ob = item as Student
                console.log(ob.name + ', ' + ob.school
                    + '(' + ob.grade + ')')
                break
                case 'Employee':
                ob = item as Employee
                console.log(ob.name + ':' + ob.title
                    + ':' + ob.department)
                break
                default:
                console.log('cannot print.')
            }
        }
    }
}

### テンプレートリテラル
${}で埋め込む

const data = [10, 20, 30]
const msg = `data is [${data}]`
console.log(msg)
const result = `total is ${data[0]+data[1]+data[2]} !`
console.log(result)

### テンプレートリテラル型

type val_name = "sample"|"private"|"public"
type data_type = `${val_name}_data`
type prop_type = `${val_name}_property`
type method_type = `${val_name}_method`

const s:data_type = "sample_data"
const t:prop_type = "public_property"
const u:method_type = "private_method"
const v:data_type = "personal_data"

### レコード型

type prop_name = 'name' | 'mail' | 'age'
type Person = Record<prop_name, string|number>

const taro:Person = {
    name: 'taro',
    mail:'taro@gmail.com',
    age: 39
}

console.log(taro)

### Pick型

type person_data = {
    name:string,
    mail:string,
    address:string,
    age:number
}

type person_keys = 'name' | 'age'
type human_keys = 'name' | 'mail' | 'address'

type person = Pick<person_data, person_keys>
type human = Pick<person_data, human_keys>

const taro:person = {
    name: 'taro',
    age: 39
}
const hana:human = {
    name: 'hanako',
    mail: 'hanako@gmail.com',
    address: 'chiba'
}
console.log(taro)
console.log(hana)

### イテレータ

class MyData<T> {
    data:T[ ] = []

    constructor(...data: T[]){
        this.data = data
    }

    add(val:T) {
        this.data.push(val)
    }

    [Symbol.iterator](){
        let pos = 0;
        let items = this.data;

        return {
            next(): IteratorResult<T>{
                if(pos < items.length) {
                    return {
                        done: false,
                        value: items[pos++]
                    }
                } else {
                    return {
                        done: true,
                        value: null
                    }
                }
            }
        }
    }
}
const data = new MyData<string>('one','two','three')

for(let item of data){
    console.log(item)
}

OKなのかNGなのかすらわからん

[TypeScript] メモアプリ

index.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
	<script src="main.js"></script>
</head>
<body>
	<h1 class="bg-primary text-white p-2">Memo page</h1>
	<div class="container">
		<p class="h5">type message:</p>
		<div class="alert alert-primary">
			<input type="text" class="form-control" id="message">
			<button class="btn btn-primary mt-2" id="btn">
			Save</button>
		</div>
		<table class="table" id="table"></table>
		<div class="text-center">
			<button class="btn btn-danger mt-4" id="initial">
				Initialize
			</button>
		</div>
	</div>
</body>
</html>

index.ts

let table:HTMLTableElement
let message:HTMLInputElement

function showTable(html:string){
	table.innerHTML = html
}

function doAction(){
	const msg = message.value
	memo.add({message:msg, date:new Date()})
	memo.save()
	memo.load()
	showTable(memo.getHtml())
}

function doInitial(){
	memo.data = []
	memo.save()
	memo.load()
	message.value = ''
	showTable(memo.getHtml())
}

type Memo = {
	message:string,
	date:Date
}

class MemoData {
	data:Memo[] = []

	add(mm:Memo):void {
		this.data.unshift(mm)
	}

	save():void {
		localStorage.setItem('memo_data', JSON.stringify(this.data))
	}
	load():void{
		const readed = JSON.parse(localStorage.getItem('memo_data'))
		this.data = readed ? readed : []
	}

	getHtml():string {
		let html = '<thead><th>memo</th><th>data</th></thead><tbody>'
		for(let item of this.data){
			html += '<tr><td>' + item.message + '</td><td>'
				+ item.date.toLocaleString() + '</td></tr>'
		}
		return html + '</tbody>'
	}
}

const memo = new MemoData()

window.addEventListener('load', ()=> {
	table = document.querySelector('#table')
	message = document.querySelector('#message')
	document.querySelector('#btn').addEventListener('click', doAction)
	document.querySelector('#inital').addEventListener('click', doInitial)
	memo.load()
	showTable(memo.getHtml())
})

これなんだよな やりたいこと

[TypeScript] クラス2

### インターフェイス

interface Human {
    name:string
    print():void
}

class Person implements Human {
    name:string = 'no-name'
    mail:string
    age:number

    constructor(name:string, mail:string = 'no-mail', age:number = -1){
        this.name = name
        this.mail = mail
        this.age = age
    }

    print():void {
        console.log(this.name + '(' + this.mail + ',' + this.age + ')')
    }
}

class Student implements Human {
    name:string = 'no-name'
    school?:School
    grade?:number

    constructor(name:string,school?:School, grade?:number){
        this.name = name
        this.school = school
        this.grade = grade
    }

    print():void {
        let gd:string = this.grade ? String(this.grade) : '-'
        console.log(this.name + '(' + this.school + ' school: ' + gd + ' grade)') 
    }
}

const taro:Person = new Person('taro', 'taro@yamada', 39)
const hanako:Student = new Student('hanako', School.high, 39)
const sachiko:Person = new Person('sachiko')
const jiro:Student = new Student('jiro')

const data:Human[] = [taro, hanako, sachiko, jiro]

for(let item of data){
    item.print()
}

### インターフェイスの継承

interface People extends Human {
    birth:Date
}

class Employee implements People {
    name:string = 'no-name'
    company:string = ''
    birth:Date = new Date()

    constructor(nm:string, cm:string, bth:Date){
        this.name = nm
        this.company = cm
        this.birth = bth
    }

    print():void {
        console.log(this.name + ' [' + this.company + ']')
    }
}

const ichiro = new Employee('ichiro',
    'Baseball Inc.', new Date('1982/10/10'))
ichiro.print()

### 静的メンバー

class StaticHuman {
    static fullname:string
    static age:number
    
    static set(nm:string, ag:number):void {
        this.fullname = nm
        this.age = ag
    }

    static print():void {
        console.log(this.fullname + '(' + this.age + ')')
    }
}

StaticHuman.set('taro',39)
StaticHuman.print()
StaticHuman.set('hanako',29)
StaticHuman.print()

### パラメータープロパティ

class Human {
    constructor(readonly name:string, readonly age:number){

    }

    print():void {
        console.log(this.name + '(' + this.age + ')')
    }
}

const taro = new Human('taro', 39)
taro.print()
const hana = new Human('hanako', 28)
hana.print()

### 総称型

class Data<T> {
    data?:T[]

    constructor(...item:T[]){
        this.data = item
    }

    print():void {
        if(this.data) {
            for(let item of this.data){
                console.log(item)
            }
        } else {
            console.log('no data...')
        }
    }
}

const data1 = new Data<string>('one','two','three')
const data2 = new Data<number>(123,456,78,90)
data1.print()
data2.print()

### ユーティリティ型
Readonly, Required, Partial

type Human = {
    name:string
    mail?:string
    age?:number
}

class Person {
    human:Required<Human>

    constructor(nm:string, ml:string, ag:number){
        this.human = {name:nm, mail:ml, age:ag}
    }

    print():void {
        console.log(this.human.name
            + ' (' + this.human.age + '::'
            + this.human.mail + ')')
    }
}
const taro = new Person('taro', 'taro@yamada', 39)
taro.print()

OK

[TypeScript] クラス1

### クラス

class Person {
    name:string = 'no-name'
    mail?:string
    age?:number
    print():void {
        const ml:string = this.mail ? this.mail : 'no-mail'
        const ag:number = this.age ? this.age : -1
        console.log(this.name + '(' + ml + ',' + ag + ')')
    }
}

const taro = new Person()
taro.name = 'taro'
taro.mail = 'taro@gmail.com'
taro.age = 39
taro.print()

### コンストラクタ

class Person {
    name:string = 'no-name'
    mail?:string
    age?:number

    constructor(name:string, mail:string = 'no-mail', age:number = -1){
        this.name = name
        this.mail = mail
        this.age = age
    }

    print():void {
        console.log(this.name + '(' + this.mail + ',' + this.age + ')')
    }
}

const taro = new Person('taro', 'taro@gmail.com', 39)
const hanako = new Person('hanako', 'hanako@gmail.com')
const sachiko = new Person('sachiko')

taro.print()
hanako.print()
sachiko.print()

### インスタンスのクラスを調べる

console.log(taro instanceof Person === hanako instanceof Person === true)

console.log(taro.constructor.name)
console.log(hanako.constructor.name)
console.log(Person.name)

### クラスの継承
extendsで継承する

enum School {
    junior='junior',
    juniorHigh = 'juniorHigh',
    high = 'high',
    other = 'other'
}

class Student extends Person {
    school?:School
    grade?:number

    constructor(name:string, school:School, grade:number){
        super(name)
        this.school = school
        this.grade = grade
        switch(school){
            case School.junior:
            this.age = 6 + this.grade; break
            case School.juniorHigh:
            this.age = 12 + this.grade; break
            case School.high:
            this.age = 15 + this.grade; break
            default:
            this.age = -1
        }
    }
}

const taro = new Person('taro', 'taro@gmail.com', 39)
const hanako = new Student('hanako', School.high, 2)

taro.print()
hanako.print()

### メソッドのオーバーライド
– 継承しているクラスの中にメソッドを追加する

    print():void {
        let gd:string = this.grade ? String(this.grade) : '-'
        switch(this.grade){
            case 1:gd += 'st'; break
            case 2:gd += 'nd'; break
            case 3:gd += 'rd'; break
            default: gd += 'th'
        }
        console.log(this.name + '(' + this.school + ' school: ' + gd + ' grade)')
    }

### アクセス修飾子
public: 外部から自由にアクセス
protected: クラスおよびクラスを継承したサブクラス
private: クラス内のみ

    protected name:string = 'no-name'
    private mail:string
    public age:number

### setterとgetter

class Student extends Person {
    school?:School
    private grade_num:number = -1
    get gradeN():number {
        return this.grade_num
    }
    set gradeN(n:number){
        this.grade_num = n
        this.grade = String(n)
    }
    private gr_str:string = ''
    get grade(): string {
        return this.gr_str
    }
    private set grade(pr:string){
        let gd = pr
        switch(this.gradeN){
            case 1: gd += 'st'; break
            case 2: gd += 'nd'; break
            case 3: gd += 'rd'; break
            default: gd += 'th'
        }
        this.gr_str = gd
    }

    constructor(name:string, school:School, grade:number){
        super(name)
        this.school = school
        this.gradeN = grade
    }

    print():void {
        let gd:string = this.grade ? String(this.grade) : '-'
        console.log(this.name + '(' + this.school + ' school: ' + gd + ' grade)')
    }
}

ふむ

[TypeScript] オブジェクト

オブジェクトとは「値と処理をひとまとめに保管し、名前で取り出せるようにしたもの」
プロパティ: オブジェクトの中の値
メソッド: オブジェクトの中の関数

同じプロパティやメソッドを使う場合、this. と書く

const person = {
    name: "taro",
    age: 39,
    print: function(): void {
        console.log(this.name + '('
            + this.age + ')')
    }
}

person.print()
person.name = 'hanako'
person.age = 28
person.print()

### Objectによる生成

const person = Object()
person.name = "taro"
person.age = 39
person.print = function():void {
    console.log(this.name + '('
        + this.age + ')')
}

### ファクトリ関数
ファクトリとは値を作成するもの

function Person(n:string, a:number):
        {name:string, age:number, print:()=>void}{
    return {
        name: n,
        age: a,
        print: function(){
            console.log(this.name +
                '(' + this.age + ')')
        }
    }
}

const taro = Person('taro', 39)
const hana = Person('hanako', 28)
taro.print()
hana.print()

### オブジェクトに引数を通過う

type person = {name:string, age:number}

function setData(ob:person, n:string, a:number):person {
    ob.name = n
    ob.age = a
    return ob
}

const ob1:person = {name:'taro', age:39}
const ob2:person = setData(ob1, 'hanako', 28)

console.log(ob1)
console.log(ob2)

### オブジェクトの分割代入

type person = {name:{first:string, second:string}, age:number}

const ob1:person = {name:{first:'taro', second: 'yamada'}, age:39}
const {name:{first, second}, age} = ob1
console.log(first + "-" + second + '::' + age)

### プロパティのオプションとReadonly

type person = {readonly name:string, mail?:string, age?:number, print:()=>void}

const ob1:person = {
    name: 'taro',
    age: 39,
    print:function():void {
        console.log(this.name + ':' + this.age)
    }
}

const ob2:person = {
    name: 'hanako',
    mail: 'hanako@gmail.com',
    print:function():void {
        console.log(this.name + ':' + this.mail)
    }
}
ob1.print()
ob2.print()

[TypeScript] コマンドライン引数から緯度・経度から距離を測定したい

$ npm install @turf/distance
$ npm install @turf/helpers

index.ts

import distance from '@turf/distance'
import { point } from '@turf/helpers'

const tokyo = point([139.69198077115493, 35.68978025468156])
const osaka = point([135.51980022509665, 34.6865543538711])
const result = distance(tokyo, osaka, {units: 'kilometers'})
console.log(result)

$ node sample.js
395.1818245563336

これをコマンドライン引数で書くと

import distance from '@turf/distance'
import { point } from '@turf/helpers'

console.log("Node path = " + process.argv[0])
console.log("Script file path = " + process.argv[1])

const startLongitude = Number(process.argv[2])
const startLatitude = Number(process.argv[3])
const destLongitude = Number(process.argv[4])
const destLatitude = Number(process.argv[5])

const start = point([startLongitude, startLatitude])
const dest = point([destLongitude, destLatitude])
const result = distance(start, dest, {units: 'kilometers'})
console.log(result)

これにアロー関数を追加する

const f = (name:string, speed:number): void => {
	let time = result / speed
	console.log("時速" + speed + "km/hの" + name + "だと、" + time + "時間かかります。")
}

f("新幹線", 200)
f("高速バス", 120)

$ node sample.js 139.69198077115493 35.68978025468156 135.51980022509665 34.6865543538711
395.1818245563336
時速200km/hの新幹線だと、1.975909122781668時間かかります。
時速120km/hの高速バスだと、3.29318187130278時間かかります。

process.argvを変数に代入すると冗長になるから直接書いても良さそうだな
高速バスで東京大阪は3.2時間以上かかるから、実際のところ60km/h ってところか。

うむ、書きながら勉強になるな

[TypeScript] 高度な関数

### 例外処理
try, catch(e), finallyで書く
以下のスクリプトでは

const f = (arr?:any[]): void => {
    let res = 'Array: '
    for(let i of arr){
        res += String(i) + '\t'
    }
    console.log(res)
}

try {
    f(['ok', 'NG'])
    f([10, 20, 30])
    f()
} catch(e){
    console.log(e.message)
}

“arr is not iterable”

### 例外を発生させる関数

const f = (n:number):[number, Error?] => {
    if (n < 0){
        return [n, Error("negative number")]
    }
    let total = 0
    for(let i = 1; i<= n; i++)
        total += i
    return [total]
}

let[res1, err1] = f(100)
if(err1 == undefined)
    console.log(res1)
else console.log(err1)

let[res2, err2] = f(-100)
if(err2 == undefined)
    console.log(res2)
else console.log(err2)

### Errorをthrowする
throw Error

const f = (n:number):number => {
    if (n < 0){
        throw Error("negative!")
    }
    let total = 0
    for(let i = 1; i<= n; i++)
        total += i
    return total
}

let re1 = f(100)
console.log(re1)
let re2 = f(-100)
console.log(re2)

### ジェネリクス
定義の段階では型を指定せず、利用する場合に特定の型を使う
function 関数 ()引数:戻り値

function getRnd<T>(values: T[ ]): T {
    const r = Math.floor(Math.random() * values.length)
    return values[r]
}

const data1 = [0, 2, 4, 5, 6, 10]
const data2 = ['グー','チョキ','パー']
const data3 = [true, false]

for(let i = 0; i < 10; i++){
    const re1 = getRnd(data1)
    const re2 = getRnd(data2)
    const re3 = getRnd(data3)
    const res = re1 + '(' + typeof(re1) + ')\t'
        + re2 + '(' + typeof(re2) + ')\t'
        + re3 + '(' + typeof(re3) + ')'
    console.log(res)
}

### ジェネレーターと遅延評価
呼び出すごとに新しい値を取り出す関数
function* と yield(待ち状態)を作ります
nextで次の数字を呼び出す

function* fibo(n:number){
    let n1 = 0
    let n2 = 1
    for(let i = 0; i <= n; i++){
        yield n1
        let n3 = n1 + n2
        n1 = n2
        n2 = n3
    }
}

const n = 10
let fb = fibo(n)
for(let i = 0; i <= n + 3; i++){
    let ob = fb.next()
    console.log(ob.value)
}

### 非同期処理とpromise
処理を開始すると、待ち続けることなく次の処理に進んでいく
promiseは事後処理を呼び出して必要な作業を行う

function 関数(引数): Promise {
	return new Promise ((関数) => {


		関数()
	})
}
const f = (n:number, d:number): Promise<number> => {
    console.log("start:" + n)
    return new Promise((f) => {
        let total = 0
        for(let i = 1; i <= n; i++)
            total += i
        setTimeout(() => {
            f(total)
        }, d)
    })
}

const cb = (n:number) => {
    console.log("result:" + n)
}

f(10, 300).then(cb)
f(100, 200).then(cb)
f(1000, 100).then(cb)

プロミスを理解しないといけないことはわかった

[TypeScript] 関数2

### 無名関数
– 関数名がないもの

const f = function(name:string):void {
    console.log("hello, " + name)
}

f("taro")
f("hanako")

### アロー関数
(引数): 戻り値 => 実行する処理

const f = (name:string):void => {
    console.log("hello, " + name)
}

console.log(typeof(f)) とすると “function” がreturnとなる

### 内部関数
関数の中でしか使えない関数

const f = (n:number)=> {
    const inF = (n:number):void => {
        console.log("value:" + n)
    }
    let total = 0
    for (let i = 1; i<= n; i++){
        total += i
        inF(total)
    }
}
f(10)

### 引数に関数を使う

const func = (n:number, f:Function):void => {
    let res = f(n)
    console.log("Result:" + res)
}

const double = (n:number) => n * 2
const total = (n:number) => {
    let total = 0
    for (let i = 1; i <= n; i++)
        total += i
    return total
}

const num = 100
func(num, double)
func(num, total)

### 数値とテキストの関数を引数にする
charAtは「●文字目」を得るもの

const func = (n:number, f:(n:number)=>number|string):void => {
    let res = f(n)
    console.log("Result:" + res)
}

const double = (n:number) => n * 2
const word = (n:number):string => {
    const w = ['〇','一','二','三','四','五','六','七','八','九']
    const s = String(n)
    let res:String[] = []
    for(let i = 0; i< s.length; i++){
        let c = s.charAt(i)
        res.push(w[Number(c)])
    }
    return res.join('')
}

const num = 1230
func(num, double)
func(num, word)

### 戻り値に関数を使う

const f = (tax:number):(n:number)=> number => {
    return (n:number)=> n * (1 +tax)
}

const f1 = f(0.1)
const f2 = f(0.8)

const price = 123400
console.log(f1(price))
console.log(f2(price))

### クロージャー
定義された環境を保ち、その中で動く関数をクロージャという

const f = (n:number):() => number => {
    let count:number = 0
    return ():number => {
        count += n
        return count
    }
}

const f1 = f(1)
const f2 = f(2)
const f3 = f(3)

for(let i = 0; i < 10; i++){
    console.log(f1() + '\t' + f2() + '\t' + f3())
}

ちょっと難しくなってきた

[TypeScript] 関数1

function hello(name:string) {
    console.log("Hello " + name + "!")
}

hello("taro")
hello("hanako")

引数に型を指定する

### 変数のスコープ
varは全体で利用可、letは宣言した構文内
– var

function total(max:number){
    var num = 0
    for(var i = 1; i < max; i++){
        num += i
    }
    console.log("total:" + (num + i))
}

total(100)
total(200)
total(300)

– letにするとエラーになる

let num = 0
    for(let i = 1; i < max; i++){
        num += i
    }
    console.log("total:" + (num + i))

Cannot find name ‘i’.

### 戻り値
– 関数の処理実行後に返される値を戻り値という
– 何も戻さない場合はvoidを指定する

function total(max:number):number{
    let num = 0
    for(let i = 1; i < max; i++){
        num += i
    }
    return num
}

function printTotal(n:number):void {
    let res = total(n)
    console.log(n + "までの合計:" + res)
}

printTotal(123)
printTotal(1234)
printTotal(12345)

### 複数の値を戻す
タプルを使って複数の値の型を記述する

function calcTax(price:number):[price:number, tax:number]{
    const p = price / 1.1
    const t = price - p
    return [p, t]  
}

function printTax(price:number): void {
    const [pr, tx] = calcTax(price)
    console.log(price + "の本体価格:" + pr + ", 税額:" + tx)
}

printTax(2750)
printTax(3080)

### 引数に条件型

function printPerson(id:number | string, name:string, age:number):void{
    switch(typeof(id)){
        case 'string':
        console.log('your id is "' + id + '".')
        break
        case 'number':
        console.log("No," + id)
        break
        default:
        console.log('wrong id ...')
    }
    console.log('Name:' + name + '(' + age + ')')
}

printPerson(10, "taro", 39)
printPerson("flower", "hanako", 20)

### オプション引数の関数
オプション引数はnullを許容する

function printPerson(name?:string, age?:number):void{
    const nameval = name ? name : "no-name"
    const ageval = age ? String(age) : '-'
    console.log('Name:' + nameval + '(' + ageval + ')')
}

printPerson("taro", 39)
printPerson("hanako")
printPerson()

– 引数に初期値を入れる方法も一般的

### 可変長引数

const f = (...data:number[]):number => {
    let total = 0
    for (let i of data){
        total += i
    }
    return total
}

console.log(f(1,2,3,4,5))
console.log(f(10,20,30,40,50,60,70))
console.log(f(123,456,67,89))

なるほど、この数時間でプログラミングの理解がかなり進んだ

[TypeScript] 基礎文法2

### 配列
– 配列の作り方は[valu1, value2, …] と new Array()がある

const data = [10, 20, 30]
const total = data[0] + data[1] + data[2]
console.log('total:' + total)

– 変更不可の配列

let data2:readonly number[] = [10, 20, 30]
data2[0] = 100

Index signature in type ‘readonly number[]’ only permits reading.

– 配列の場合は for(let variables of value) を使う

const data = [100, 98, 76, 59, 87]
let total = 0
for (let item of data){
    total += item
}

const av = total / data.length
console.log('total:' + total)
console.log('average:' + av)

– 配列の要素の操作
L 最初に追加
data.unshift(value)
L 最初を削除
data.shift()
L 最後に追加
data.push(value)
L 最後を削除
data.pop()

let data:any = [10, 20, 30, 40, 50]

console.log(data)
for(let i = 0; i < 5; i++){
    data.pop()
    data.unshift('⭐️')
    console.log(data)
}

### タプル
変数の型を指定することで、異なる型も入れることができる

let me:[string, number]
let you:[string, number]

me = ['taro', 39]
you = ['hanako', 'hanako@gmail.com']

### enum
{}に用意した値しか設定できない。それ以外の値は使えない

enum janken {goo, choki, paa}

const you = janken.goo

switch(you) {
    case janken.goo:
    console.log('あいこ')
    break
    case janken.choki:
    console.log('win')
    break
    case janken.paa:
    console.log('lose')
    break    
}

### 型エイリアス
型に別名を入れることでタプルをわかりやすくする

type name = string
type age = number

let me:[name, age]
let you:[age, name]

me = ['taro', 39]
you = [29, 'hanako']

console.log(me)
console.log(you)

typeで型を指定

type name = string
type mail = string
type age = number
type person = [name, mail, age]

const taro:person = ['taro', 'taro@gmail.com', 39]
const hanako:person = ['hanako', 'hanako@gmail.com', 24]
const sachiko:person = ['sachiko', 'sachiko@gmail.com', 17]

const data:person[] = [taro, hanako, sachiko]

for(let item of data){
    console.log(item)
}

リテラル型
L リテラルとは直接ソースコードに書かれる値
L 指定した値しかない型

type hello = "hello"
type by = "bye"
type name = string

const taro:name = "taro"
const msg1:hello = "hello"
console.log(msg1 + ", " + taro)
const hanako:name = "hanako"
const msg2:by = "bye"
console.log(msg2 + ", " + hanako)

conditional types
L “|”を使うことで、enumと同じような使い方ができる

type msg = "hello" | "bye"
type name = string

const taro:name = "taro"
const msg1:msg = "hello"
console.log(msg1 + ", " + taro)
const hanako:name = "hanako"
const msg2:msg = "bye"
console.log(msg2 + ", " + hanako)

### 型チェック
– typeofで型チェックを行う

type id = number | string

const idA:id = "taro"
const idB:id = 123

const tp = idA

switch(typeof(tp)){
    case "number":
    console.log(tp + " is number")
    break
    case "string":
    console.log(tp + " is string")
    break
    default:
    console.log("type is undefined")
}

### ユーティリティ型
性質を付加する特殊な型
Readonly<●●>は総称型と呼ばれる機能

type data = [string, number]
type ReqData = Readonly<data>

const x:data = ["taro", 39]
const y:ReqData = ["hanako", 28]

x[1] = 28
y[1] = 17

Cannot assign to ‘1’ because it is a read-only property.

### シンボル
全ての値がユニークであることを保証される型
variable = Symbol(value)

const a1:string = "ok"
const b1:string = "ok"

console.log(a1 == b1)
console.log(a1 === b1)

const a2:unique symbol = Symbol("ok")
const b2:unique symbol = Symbol("ok")

console.log(a2 == b2)
console.log(a2 === b2)

This condition will always return ‘false’ since the types ‘typeof a2’ and ‘typeof b2’ have no overlap.
This condition will always return ‘false’ since the types ‘unique symbol’ and ‘string’ have no overlap.

### nullかも知れない値
値がないことを許容するために”?”をつける
絶対にnullではない場合、”!”をつける

type data = [name:string, age?:number]

const taro:data = ["taro", 39]
const hanako:data = ["hanako"]
console.log(taro)
console.log(hanako)

大分味が出てきた