2
2

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 1 year has passed since last update.

Python経験者のためのTypeScript入門(途中)

Last updated at Posted at 2022-05-12

はじめに

  • コードの動作確認
    • TypeScript
      ちょっとしたコードの動作確認には TypeScript Playground が便利。
      コードを書いてRunボタンで実行できる。TypeScriptの環境を作るのは結構めんどくさいので重宝する。

    • Python
      Trinket CodePlayground などがあるが、適当な.py ファイル作って実行すればいいと思う。


プリミティブ型の変数定義

  • Python
    Pythonには var, let, const のような使い分けはなく、全てTypeScriptのletと同じ。

  • TypeScript
    TypeScriptの変数定義には var, let, const の3種類ある。
    可能な限り const を使う。

    var と let はどちらも再代入可能な変数を定義するが、
    var は古い書き方なので使わない方が良い。全て let でOK。

    JavaScriptでvarが非推奨な理由を整理してみた

    const は定数を定義する。
    const でもオブジェクト型であれば要素の変更はできる。

Python
s: str = 'string'
i: int = 0
f: float = 0.0
b: bool = True

# 再代入
s = s + 'xxx'  # or s += 'xxx'
i = i + 100    # or i += 100
f = f + 100.0  # or f += 100.0
b = not b

print(s)  # 'stringxxx'
print(i)  # 100
print(f)  # 100.0
print(b)  # False
TypeScript

let

let s: string = 'string'
let i: number = 0    // TypeScriptの型に integer はない。
let f: number = 0.0  // TypeScriptの型に  float  はない。
let b: boolean = true

// 再代入
s = s + 'xxx'  // or s += 'xxx'
i = i + 100    // or i += 100
f = f + 100.0  // or f += 100.0
b = !b

console.log(s)  // "stringxxx"
console.log(i)  // 100
console.log(f)  // 100
console.log(b)  // false

const

const s: string = 'string'
const i: number = 0
const f: number = 0.0
const b: boolean = true

// 再代入は全て不可(エラー)
s = s + 'xxx'  // or s += 'xxx'
i = i + 100    // or i += 100
f = f + 100.0  // or f += 100.0
b = !b

オブジェクト型の変数定義(配列)

Python
a: [str, int, float, bool] = ['string', 0, 0.0, True]

# 要素の変更
a[0] = a[0] + 'xxx'  # or a[0] += 'xxx'
a[1] = a[1] + 100    # or a[1] += 100
a[2] = a[2] + 100.0  # or a[2] += 100.0
a[3] = not a[3]

print(a[0])  # 'stringxxx'
print(a[1])  # 100
print(a[2])  # 100.0
print(a[3])  # False

# 再代入
a = ['str', 9, 9.9, False]
print(a)  # ['str', 9, 9.9, False]
TypeScript

let

let a: [string, number, number, boolean] = ['string', 0, 0.0, true]

// 要素の変更
a[0] = a[0] + 'xxx'  // or a[0] += 'xxx'
a[1] = a[1] + 100    // or a[1] += 100
a[2] = a[2] + 100.0  // or a[2] += 100.0
a[3] = !a[3]

console.log(a[0])  // 'stringxxx'
console.log(a[1])  // 100
console.log(a[2])  // 100.0
console.log(a[3])  // false

// 再代入
a = ['str', 9, 9.9, false]
console.log(a)  // ['str', 9, 9.9, false]

const

const a: [string, number, number, boolean] = ['string', 0, 0.0, true]

// 要素の変更は可能( a への再代入ではないため)
a[0] = a[0] + 'xxx'  // or a[0] += 'xxx'
a[1] = a[1] + 100    // or a[1] += 100
a[2] = a[2] + 100.0  // or a[2] += 100.0
a[3] = !a[3]

// 再代入は不可(エラー)
a = ['str', 9, 9.9, false]

オブジェクト型の変数定義(辞書 or オブジェクト)

Python
from typing import TypedDict


class Dic(TypedDict):
    s: str
    i: int
    f: float
    b: bool


dic: Dic = {
    's': 'string',
    'i': 0,
    'f': 0.0,
    'b': True,
}

# 要素の変更
dic['s'] = dic['s'] + 'xxx'  # or dic['s'] += 'xxx'
dic['i'] = dic['i'] + 100    # or dic['i'] += 100
dic['f'] = dic['f'] + 100.0  # or dic['f'] += 100.0
dic['b'] = not dic['b']

print(dic['s'])  # 'stringxxx'
print(dic['i'])  # 100
print(dic['f'])  # 100.0
print(dic['b'])  # False

# 再代入
dic = {
    's': 'str',
    'i': 9,
    'f': 9.9,
    'b': False,
}
print(dic)  # {'s': 'str', 'i': 9, 'f': 9.9, 'b': False}
TypeScript

let

interface Obj {
    s: string
    i: number
    f: number
    b: boolean
}

let obj: Obj = {
    s: 'string',
    i: 0,
    f: 0.0,
    b: true,
}

// 要素の変更
obj.s = obj.s + 'xxx'  // or obj.s += 'xxx'
obj.i = obj.i + 100    // or obj.i += 100
obj.f = obj.f + 100.0  // or obj.f += 100.0
obj.b = !obj.b

console.log(obj.s)  // 'stringxxx'
console.log(obj.i)  // 100
console.log(obj.f)  // 100
console.log(obj.b)  // false

// 再代入
obj = {
    s: 'str',
    i: 9,
    f: 9.9,
    b: false,
}
console.log(obj)  // { 's': 'str', 'i': 9, 'f': 9.9, 'b': false }

const

interface Obj {
    s: string
    i: number
    f: number
    b: boolean
}

const obj: Obj = {
    s: 'string',
    i: 0,
    f: 0.0,
    b: true,
}

// 要素の変更は可能( obj への再代入ではないため)
obj.s = obj.s + 'xxx'  // or obj.s += 'xxx'
obj.i = obj.i + 100    // or obj.i += 100
obj.f = obj.f + 100.0  // or obj.f += 100.0
obj.b = !obj.b

// 再代入は不可(エラー)
obj = {
    s: 'str',
    i: 9,
    f: 9.9,
    b: false,
}

「const=定数 なのに変更できるってどういうこと?」ってなりそう。

Pythonだけやってた私は結構混乱しましたが、型エラーで悩んでるうちに理解できました。

参考: ミュータブルな型とイミュータブルな型の相違を知ろう

とりあえずオブジェクト型は const で定義してみましょう。

オブジェクト型を再代入しなければならない状況はあまりありません。

アトリビュートの参照についての補足
Python

dic['key']で参照する

my_dict = {'key': 'value'}

# この書き方はできない
my_dict.key  # 例外 AttributeError: 'dict' object has no attribute 'key'.

my_dict['key']        # 'value'
my_dict['wrong_key']  # 例外 KeyError: 'wrong_key'

# .get()を使うことで例外を避けることができる
my_dict.get('key')    # 'value'
my_dict.get('wrong_key')  # None

# .get()の第2引数を渡すことでキーがなかった場合のデフォルト値を設定できる
my_dict.get('wrong_key', 'default_value')  # default_value
TypeScript

obj.key, obj['key']どちらでも参照できる。
Pythonと異なり、存在しないキーを参照しようとしても例外にはならない。

const myObj = { key: 'value' }

// どちらでもちゃんと 'value' を参照できる
myObj.key     // こっちの方が短く書けて良い
myObj['key']  // キー名に日本語が含まれる場合などはこちらを使う必要がある

myObj.wrongKey      // undefined
myObj['wrong_key']  // undefined

// ? を付けることで型エラーを回避できることも
myObj?.wrongKey      // undefined

特殊な型

Pythonの None とTypeScriptの null は同じと考えていい。

TypeScriptには undefinedSymbol があるが、Symbol を使用する機会はかなり少ない。

まだ値が代入されていない変数は undefined 型となる。

let x
console.log(x) // undefined

Pythonで同じことをしようとすると例外になる。

print(x)

Traceback (most recent call last):
File "C:\Program Files\Python310\lib\code.py", line 90, in runcode
  exec(code, self.locals)
File "<input>", line 1, in <module>
NameError: name 'x' is not defined

関数の定義

Python
from typing import TypedDict


class Dic(TypedDict):
    k1: str
    k2: int
    k3: float
    k4: bool


def my_func(s: str, i: int, f: float, b: bool) -> Dic:
    return {'k1': s, 'k2': i, 'k3': f, 'k4': b}

# デフォルト値ありの関数
def my_func_with_default(s: str = '', i: int = 0, f: float = 0.0, b: bool = False) -> Dic:
    return {'k1': s, 'k2': i, 'k3': f, 'k4': b}


if __name__ == '__main__':
    x = my_func('string', 0, 0.0, True)
    print(x)  # {'k1': 'string', 'k2': 0, 'k3': 0.0, 'k4': True}

    # 全てデフォルト値
    y = my_func_with_default()
    print(y)  # {'k1': '', 'k2': 0, 'k3': 0.0, 'k4': False}

    # 引数を1つだけ指定
    z = my_func_with_default('custom string')
    print(z)  # {'k1': 'custom string', 'k2': 0, 'k3': 0.0, 'k4': False}
TypeScript
interface Obj {
    k1: string
    k2: number
    k3: number
    k4: boolean
}

function myFunc(s: string, i: number, f: number, b: boolean): Obj {
    return { k1: s, k2: i, k3: f, k4: b }
}

// デフォルト値ありの関数
function myFuncWithDefault(s: string = '', i: number = 0, f: number = 0.0, b: boolean = false): Obj {
    return { k1: s, k2: i, k3: f, k4: b }
}

const x = myFunc('string', 0, 0.0, true)
console.log(x)  // {"k1": "string", "k2": 0, "k3": 0, "k4": true}

// 全てデフォルト値
const y = myFuncWithDefault()
console.log(y)  // {"k1": "", "k2": 0, "k3": 0, "k4": true}

// 引数を1つだけ指定
const z = myFuncWithDefault('custom string')
console.log(z)  // {"k1": "custom string", "k2": 0, "k3": 0, "k4": false}
TypeScriptのアロー関数

TypeScriptの関数定義方法にはいろんな書き方があり、結構混乱します。
以下の3つの関数は全て同じ動作をします。

厳密には通常の関数とアロー関数ではthis(Pythonのself)の扱いが異なります

// 通常の関数
function myFunc(x: string): string {
    return x
}

// アロー関数
const myArrowFunc = (x: string): string => {
    return x
}

// アロー関数定義 + return の省略
const myArrowFunc2 = (x: string): string => x

myFunc('aaa')
myArrowFunc('bbb')
myArrowFunc2('ccc')

クラスの定義

Python
TypeScript

文字列の操作

Python
TypeScript

数値の操作

Python
TypeScript

配列の操作

Python
TypeScript

オブジェクト(辞書)の操作

Python
TypeScript

条件分岐

Python
if x > 5:
  print('x > 5')
elif x == 5:
    print('x == 5')
elif x != -100:
    print('x != -100')
else:
    print('else')

# ----------------------------
if 0 < x and x <= 10:
    print('0 < x and x <= 10')

# こう書いた方がいい
if 0 < x <= 10:
    print('0 < x <= 10')

# ----------------------------
if (0 < x and 0 <= y) or (100 < x and 100 <= y):
    print('(0 < x and 0 <= y) or (100 < x and 100 <= y)')

# ----------------------------
# None の判定は is を使う
if x is None:
    print('x is None')
    
if y is not None:
    print('y is not None')
TypeScript

==, != は基本使わないこと。
===, !== を使う。

// なんとこれはtrueになる
if (0 == '0') {
    console.log("0 == '0'")
}

// === で判定すればちゃんと false になる
if (0 === '0') {
    console.log("0 === '0'")
}

// ----------------------------
if (x > 5) {
    console.log('x > 5')
} else if (x === 5) {
    console.log('x === 5')
} else if (x !== -100) {
    console.log('x !== -100')
} else {
    console.log('else')
}

// ----------------------------
if (0 < x && x <= 10) {
    console.log('0 < x && x <= 10')
}

// ----------------------------
if ((0 < x && 0 <= y) || (100 < x && 100 <= y)) {
    console.log('(0 < x && 0 <= y) || (100 < x && 100 <= y)')
}

// ----------------------------
// 1行であれば {} を省略できる。(Pythonでもできるが非推奨)
if (true) console.log('true')
else console.log('false')

繰り返し

Python

for ... in ... :の形。
配列でインデックスも取得したいなら enumerate() を使う。
辞書なら .keys(), .values(), .items()を使う。

for x in range(10):  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    if x == 3:
        continue  # for文の先頭に戻る
    elif x == 8:
        break  # for文を抜ける
    else:
        print(x)  # 0 -> 1 -> 2 -> 4 -> 5 -> 6 -> 7

# 配列 -------------
items = ['a', 'b', 'c']

for item in items:
    print(item)  # 'a' -> 'b' -> 'c'

for i, item in enumerate(items):
    print(i)     # 0 -> 1 -> 2
    print(item)  # 'a' -> 'b' -> 'c'

# 辞書 -------------
dic = {
  'k1': 'v1',
  'k2': 'v2',
  'k3': 'v3'
}

for k in dic.keys():
    print(k)       # 'k1' -> 'k2' -> 'k3'
    print(dic[k])  # 'v1' -> 'v2' -> 'v3'

for v in dic.values():
    print(v)  # 'v1' -> 'v2' -> 'v3'

for k, v in dic.items():
    print(k)       # 'k1' -> 'k2' -> 'k3'
    print(dic[k])  # 'v1' -> 'v2' -> 'v3'
TypeScript

for (... in ...)for (... of ...) があって少しややこしいが、基本ofだけでいい。
inは配列であればインデックス(何故かnumberではなくstring)、オブジェクトであればキーを取得する。
ofは配列であれば要素、オブジェクトであれば値を取得する。

配列にfor...inはダメと言うけれど、

配列でインデックスも取得したいなら .entries() を使う。インデックスのみ取得したいなら .keys()を使う。
辞書なら Object.keys(...), Object.values(...), Object.entries(...)を使う。

for (const x of Array.from(Array(10), (_, i) => i)) {  // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  if (x === 3) continue    // for文の先頭に戻る
  else if (x === 8) break  // for文を抜ける
  else console.log(x)  // 0 -> 1 -> 2 -> 4 -> 5 -> 6 -> 7
}

// 配列 -------------
const items = ["a", "b", "c"]

for (const i in items)
    // i は string。何故…
    console.log(i)  // "0" -> "1" -> "2"

for (const i of items.keys())
    console.log(i)  // 0 -> 1 -> 2

for (const item of items)
    console.log(item)  // "a" -> "b" -> "c"

for (const [i, item] of items.entries()) {
    console.log(i)     // 0 -> 1 -> 2
    console.log(item)  // "a" -> "b" -> "c"
}

// オブジェクト -------------
const obj: Record<string, string> = {
  "k1": "v1",
  "k2": "v2",
  "k3": "v3"
}

for for (const k of Object.keys(obj)) {  // または 
    console.log(k)       // "k1" -> "k2" -> "k3"
    console.log(obj[k])  // "v1" -> "v2" -> "v3"
}

for (const v of Object.values(obj))
    console.log(v)  // "v1" -> "v2" -> "v3"

for (const [k, v] of Object.entries(obj)) {
    console.log(k)  // "k1" -> "k2" -> "k3"
    console.log(v)  // "v1" -> "v2" -> "v3"
}

型の判定

Python
TypeScript

型の変換(キャスト)

Python
TypeScript

例外処理

Python
TypeScript

言語固有の技

Python
  • リスト内包表記

    array = [1, 2, 3, 4, 5]
    new_array = [x for x in array if x > 2]
    
    print(new_array)  # [3, 4, 5]
    
    # 辞書でも同じようなことができる
    dic = {'k1': 1, 'k2': 2, 'k3': 3, 'k4': 4, 'k5': 5}
    new_dic = {k: v for k, v in dic.items() if v > 2}
    
    print(new_dic)  # {'k3': 3, 'k4': 4, 'k5': 5}
    
    # 1~100の範囲で奇数のみの配列を作る、なんてことも1行で可能
    print([x for x in range(100) if x % 2])  # [1, 3, 5, 7, 9 ... , 99]
    
TypeScript
  • 分割代入

    const obj = { k1: 1, k2: 2, k3: 3, k4: 4, k5: 5 }
    const { k1, k2, k3, k4, k5 } = obj
    
    console.log(k1)  // 1
    console.log(k2)  // 2
    console.log(k3)  // 3
    console.log(k4)  // 4
    console.log(k5)  // 5
    
  • スプレッド演算子

  • 分割代入 + スプレッド演算子

    const obj = { k1: 1, k2: 2, k3: 3, k4: 4, k5: 5 }
    const { k1, k2, ...other } = obj
    console.log(k1)     // 1
    console.log(k2)     // 2
    console.log(other)  // { "k3": 3, "k4": 4, "k5": 5 } 
    
2
2
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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?