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

TypeScriptメモ

Last updated at Posted at 2023-04-05

ここではTypeScriptの基本的な構文や気になったところをメモしていきます。
React学習のための通過点のためReactでよく使う部分を中心にメモしていく。

TypeScriptとは

TypeScriptはマイクロソフトがオープンソースで公開しているJavaScriptを拡張する形で設計されてたプログラミング言語のこと。
特徴としては以下が挙げられる。

  • JavaScriptとは異なり型付けの言語であること
  • コンパイルによるエラー検出やコードの安全性の向上
  • JavaScriptの上位互換であること

またTypeScriptはビルドツールを使って最終的にJavaScriptのコードに変換(トランスパイル)されるため、JavaScriptで実装したものとパフォーマンスの差異はない。

型の定義

変数や引数名の後ろに:型名をつける。これを型注釈といい、この型情報を変数や引数に付与することで値を制限する。
ただ、TypeScriptには型推論の機能が備わっているため、型の定義をしなかった場合自動的に型が決定される。

変数

変数の宣言にはvar``let``constを用いる。

var:再宣言や再代入が可能
let:再代入ができて再宣言ができない
const:再宣言と再代入ができない

varは関数スコープであり、letはブロックスコープであるため影響が少ないletを使うのが好ましい。

入力構文
var 変数: = 
let 変数: = 
const 変数: = 
入力例
var num: number = 1000
let flug: boolean = true
const age: string = '21'

配列

配列に型を指定するには構成する型と[]表記を用いる。

const array; string[] = []
// arrayにString型の要素を追加
array.push('Hello')

// arrayにnumber型の要素を追加
array.push(1)
// 配列の型と異なるためコンパイルエラーになる。

オブジェクト型

オブジェクトはKeyvalueによるデータ形式のインスタンスで、TypeScriptではkeyの後に:型として型を定義する。

入力構文
var 変数:{キー名:; キー名:; ...} = オブジェクト
let 変数:{キー名:; キー名:; ...} = オブジェクト
const 変数:{キー名:; キー名:; ...} = オブジェクト
入力例
// オブジェクトの宣言
const user:{name:string; age: number} = {
    name:'taro'
    age:21
}
// 値の出力
console.log(user.name)
// taro
console.log(user.age)
// 21

オブジェクトの型はプロパティに?をつけることでプロパティを省略することができる。

function printName(obj; {firstName:string; lastName?:string}){

}

// どちらもコンパイル時にエラーは出ない
printName({firstName:'taro'})
printName({firstName:'taro';lastName:'sato'})

any

anyは全ての型を許容する型のこと。

let u:any = 32
// 他の型に代入してもエラーが起きない。
let n:string = u

anyを利用すると型チェックの機能が動作しなくなるためTypeScriptの恩恵がなくなるので基本的にはanyは使わない。

関数

TypeScriptの関数では引数と戻り値に型を定義できる。

構文
function 関数名(引数:,引数:,...):戻り値の型{
    // 関数の処理
}
関数定義の例
// 関数の定義
function sayName(name:string):string{
    return `Hello ${name}`
}

// 
sayName('taro')

また引数に?をつけることで引数をオプション扱いにできる。

関数定義の例
// 関数の定義
function sayName(name:string,greeting:string):string{
    return `${greeting} ${name}`
}

// 
sayName('taro') // taro
sayName('taro','Hello') // Hello taro

引数定義の際にデフォルト値を指定することで、引数を指定しない場合値がセットされる。

関数定義の例
// 関数の定義
function sayName(name:string,greeting:string = 'Hello'):string{
    return `${greeting} ${name}`
}

// 
sayName('taro') // Hello taro
sayName('taro','Hey') // Hey taro

引数や戻り値には関数も指定できる。

関数を引数に入れる場合

function printName(firstName:string,fomatter:(name:sting) => string){
    console.log(fommatter(firstName))
}

// 名前に「さん」をつける関数を定義
function formatName(name:string):string{
    return `${name}さん`
}

printName('taro')
// taroさん

printName関数の引数であるfomatterでは**引数がstring型であるnameの戻り値がstring型である関数を示している。
実際fomatName関数は引数がstringで戻り値がstringの関数で、引数の条件を満たしている。

アロー関数

アロー関数の場合の型指定は以下の通りです。

アロー関数の構文
(引数名:引数の型):戻り値の型 => JavaScriptの式
アロー関数の例
let sayHello = (name:string):string => `Hello ${name}`

基本的な型の機能

型アサーション

型アサーションでは既に決定済みの型を上書きする機能のこと。
TypeScript上でDOMを扱うときHTMLElement(もしくはnull)として扱われます。この時HTMLElementでもdivなのかcanvasなのかはTypeScript上では判断できない。
開発者側が型を知っている場合、この型アサーション機能を使って具体的な型に上書きすることができる。

対象となる型よりも具体的になる型、または汎化させる型に変更する場合に型アサーションを使う。

型アサーション例
変数 =  as 
使用例
// main_canvasというidを持つElementを取得し、HTMLCanvasElementという型に上書きしている。(元はHTMLElement)
const myCanvas = document.getElemetById('main_canvas') as HTMLCanvasElement

型エイリアス

型エイリアスは型の定義に別の名前をつけることができる機能のこと。
この名前を参照して同じ方を複数回利用することができる。

型エイリアス例
type 型名 = 

型名は大文字始まりにすることが一般的

使用例1
// stringをNameという名前でも使えるようにしている。
type Name = string
使用例2
// number型のx,yのプロパティを持つPointという型エイリアスを定義
type Point = {
    x:number;
    y:number;
}

// Point型を引数にとる関数の定義
function printPoint(point:Point){
    // Point型のxプロパティを出力
    console.log(point.x)
    // Point型のyプロパティを出力
    console.log(point.y)
}

関数自体の型も型エイリアスで定義可能

関数の型エイリアス例
// 引数がstringで戻り値がstringの関数
type Formatter = (a: string) => string

オブジェクトのキー名を明記しなくても型エイリアスは定義可能

// オブジェクトのkeyをstring、valueをstringの型をLabelという型名にしている
type Label = {
    [key:string]: string
}

// 型エイリアスで定義した方でオブジェクトを作成
const labal:Label = {
    topTitle:'トップページのタイトル',
    topSubTitle:'トップページのサブタイトル',
    topFeature:'トップページの機能'
}

インターフェイス

インターフェイスは型エイリアスと同じく型を定義する機能のこと。
型エイリアスよりも拡張性があり、クラスと一緒に用いることが多い。

定義方法
interface 型名{
    プロパティ1:型1;
    プロパティ2:型2;
    // ...
}
使用例(オブジェクト型)
interface Point{
    x:number;
    y:number
}

型エイリアスと異なり情報を追加できる

プロパティの追加
interface Point{
    x:number;
    y:number
}
// プロパティの追加
interface Point{
    z:number;
}

インターフェースを他のインターフェースに継承することもできる

// Colorful型を宣言
interface Colorful{
    color:string;
}

// Circle型を宣言
interface Circle{
    radius:number;
}

// Colorful型とCircle型を継承してColorfulCircle型を宣言
// Colorful型とCircle型のどちらも使える
interface ColorfulCircle extends Colorful, Circle{}

const cc: ColorfulCircle = {
    color: '',
    radius: 10
}

クラス

クラスの定義方法は以下の通り。
JavaScriptのクラス記法に型が宣言できる機能が追加されただけ。

クラスの定義方法
class クラス名{
    フィールド1:型1;
    フィールド2:型2;
    //...
    
    メソッド名(変数:型名){
        //メソッドの処理
    }
}

戻り値がない場合はvoidを型名にする

クラスの定義例
class Point{
    // フィールドの定義
    x:number;
    y:number;
    
    // コンストラクタメソッドの定義
    constructor(x:number = 0, y:number = 0){
        this.x = x
        this.y = y
    }
    // moveXメソッドの定義
    moveX(n:number):void{
    this.x +=n
    }
    
    // moveYメソッドの定義
    moveY(n:number):void{
    this.y +=n
    }
}

const point = new Point()
point.moveX(10)
console.log(`${point.x}, ${point.y}`)// 10, 0

クラスもextendsを使って別のクラスを継承することができる

アクセス修飾子

アクセス修飾子でメソッドやフィールドのアクセスの範囲を制御することができる

アクセス修飾子 説明
宣言なし どこからでもアクセス可能
public どこからでもアクセス可能
private 自身のクラスからのみアクセス可能
protected 自身のクラスとサブクラスからアクセス可能

アクセス修飾子はフィールドの前に付与する。

アクセス修飾子付与
class BasePoint{
    public x: number;
    private y: number;
    protected z: number;
}

開発で重要な型

Enum型

Enum型は列挙型と呼ばれており、関連する定数まとめて定義することができる。

Enum型定義
enum 型名 = {
    定数名1,
    定数名2,
    //...
}
Enum型定義例
// Enum型のDirectionを定義
enum Direction = {
    Up,
    Down,
    Left,
    Right
}

//Direction型を参照
let direction: Direction = Direction.Left
// 2という数字が出力される
console.log(direction)

Enum型は定義された順番に0からインクリメントされた数字が代入される。
もちろん定数なので値を指定することもできる。

Enum型の定義例
enum Direction = {
    Up = 'UP',
    Down = 'DOWN',
    Left = 'LEFT',
    Right = 'LIGHT'
}

定数をまとめたオブジェクトを型として扱うことができるためバグやエラー解決が行いやすい。

ジェネリック型

ジェネリック型はクラスや関数で使う型を外部から指定できるようにして、クラスや関数に型の汎用性を持たせる機能のこと

型を引数に入れるイメージ。

ジェネリック型入力例
// クラスの定義
class クラス名<型変数>{
    //クラスの処理
}

// クラスの呼び出し
const インスタンス名 = new クラス名<型名>()

型変数を<>で囲むことで外部から型を指定できる。

ジェネリック型実装例
class Queue<T>{
    // T型の配列の初期化
    private array: T[] = []
    // 配列にT型の要素を追加
    push(item: T):void{
        this.array.push(item)
    }
    
    // 配列の一番初めの値を取り出す
    pop():T | nudefined{
        return this.array.shift()
    }
}

// Queueクラスの呼び出し
// number型を指定
const queue = new Queue<number>()
queue.push(111)
queue.push(112)
// number型ではなのでエラー
queue.push('hogehoge')

Reactコンポーネントもジェネリック型のクラスで定義されており、コンポーネントが受け取るpropsの型を外部から定義することができる。

Union型・intersection型

|&を用いて複数の型を組み合わせた型のこと。
変数や戻り値、型エイリアスに対して指定可能。

|は話集合を表すUnion型&は積集合を表すintersection型のこと。
intersection型はそれぞれのデータ型がマージされた型として扱う。

Union型使用例
// 変数の場合
let example : string | number

// 関数の引数に指定する場合
function printId(id: string | number){
    console.log(id)
}

// 型エイリアスに使う場合
type Id = string | number

function printId(id: Id){
    console.log(id)
}
intersection型使用例
type Contact = {
    name: string;
    email: string;
    phone; string
}

type Identity = {
    id: number | string;
    name: string;
}

// intersection型
type Employee = Identity & Contact
// Employeeの中身
`
{
    id: number | string;
    name: string;
    email: string;
    phone; string;
}
`

リテラル型

リテラル型は決まった文字列や数値を|で区切り扱えるデータを制御することができる型。

リテラル型の記入例
変数: 許可するデータ1 | 許可するデータ2
リテラル型例
let postStatus: 'draft' | 'published' | 'deleted'
postStatus = 'draft' // 許可されたデータなのでOK
postStatus = 'aaaa'  //許可されていないデータなのでエラー

リテラル型で指定できるデータは論理型、数値型、文字列型である。

never型

never型は何も値を持たない型。

never型には何も値を代入することはできないが、唯一never型だけ代入できる。

例外や終了しない関数の戻り値がnever型となる。
戻り値がないvoid型との違いはundefineが代入できない点にある。

TypeScriptのテクニック

Optional Chaining

?をプロパティに入れることでプロパティがUndefinedornullとなり、値が返ってこなくても処理が行える。

// nullになりうるプロパティsocialを定義
interface user{
    name: string
    social?:{
        facebook: boolean
        twitter: boolean
    }
    
}

// User型のuserを宣言
let user: User 

user = {
    name:"taro",
    social: {
        facebook: true
        twitter: true
    }
}

console.log(user.social?.facebook)
// true

// socialプロパティを定義しないuserを定義
user = {
    name: "taro"
}

console.log(user.social?.facebook)
// 定義してないがエラーは起きない

Undefinednullのまま処理が進む可能性があるためあんま使わない方がいい。

Non-null Assersion Operator

明示的に型がnullではないことを示すことができる機能。

// userがnullの場合(引数に入れない)コンパイルエラーになるが、!(Non-null Assertion)を使うことでコンパイルエラーを抑制できる。
function processUser(str:string, user?:User){
    let str = 'taro'
    let s = user!.name
}

実際は型を事前に定義した方がいいためあんまり使わない。
型アサーションで型を用意することが多い。

Non-null Assertionが良くない場合

TypeScript
let myString = "Hello": String | null
// toUpperCaseは全部大文字にするメソッド
console.log(myString!.toUpperCase())

JavaScriptにトランスパイルすると以下のようになる。

JavaScript
let myString = "Hello"
console.log(myString.toUpperCase())

この場合myStringnullになった時myString.toUpperCase()でエラーが出る。

型ガード

ifswitch文の条件分岐に型チェックを行った場合、条件分岐のブロック移行は変数の型を絞り込む機能のこと。

変数の値の型を推論してくれる機能。

型ガード例
let x: string | number = "Hello"
// typeofで型ガード
// これによりstringの場合のみの処理を分けることができる
if(typeof x === 'string'){
    // 以降xはstringとして扱われる。
    console.log(x.toUpperCase())
}

keyofオペレーター

型に対して、その型持つプロパティをUnion型で返す。

オブジェクトにあるキーを使用して何かの関数を処理を行いたい場合に安全に実装できる。

// interfaceの定義
interface User{
    name: string
    age: number
    email: string
}
type UserKey = keyof User
// 'name' | 'age' | 'email'

インデックス型

オブジェクトのプロパティが可変のとき、プロパティの型をまとめて定義できる

インデックス型例
// number型のプロパティを設定可能
type SupportVersions = {
    [env: number] = boolean
}

// string型のプロパティはエラーが起きる
let versions: SupportVersions = {
    102: false
    103: false
    // Stringだとエラー
    "104": true
}

そもそも可変のデータはあまり好まれないのであまり使わない

readonly

型エイリアス、インターフェース、クラスにおけるプロパティにreadonlyを指定すると、変更不可となる。

type User = {
    readonly name: string
    gender: string
} 
let user: User = {
    name: "taro"
    gender: "male"
}

// nameプロパティの変更はできない
user.name = "jiro"

as constで型アサーションすれば全プロパティにreadonlyが適応される。

unknown型

どのような値にも代入できる型。anyとの違いは任意の関数やプロパティにアクセスできない。

unknown型はそもそも関数やメソッド、プロパティを持たないからアクセスもクソもない。

そのため関数やプロパティにアクセスするときにはtypeofinstanceofを用いて型安全な状況を作り実行する。

// nuknown型を定義
const x: unknown = 123
const y: unknown = 'Hello'

// メソッドにはアクセスできない
console.log(x.toFixed(1))

// x自体はunknownだが値がnumberだからts側で型推論を行う(型ガード)
if(typeof x === 'number'){
    // 以降xをnumber型として扱う
    console.log(x.toFixed(1))
}

非同期のAsync/Await

TypeScriptでの非同期処理の書き方は以下の通り。
Async Awaitは簡単にいうと非同期処理を同期処理っぽくするやつ。

参考記事

// 非同期関数の定義
function fetchFromServer(id: string):Promise<{success: boolean}>{
    return new Promise(resolve => {
        setTimeout(() => {
            resolve({success: true})
            },100)
        })
}

async function asyncFunc(): Promise<string>{
    const result = await fetchFromServer('111')
    return `The result: ${result.success}`
}

(async ()=> {
    const result = await asyncFunc()
    console.log(result)
})()

asyncFunc().then(result => console.log(result))

型定義ファイル

@types/ライブラリ名JavaScriptライブラリに型情報を付与することができる。

iQueryをインストールする場合
$ npm install --save-dev @types/jquery 

TypeScriptの開発時設定

tsconfig.json

tsconfig.jsonはコンパイルする際に必要なオプションを記述するためのファイルのこと。
詳しくは以下

Prettier

スペースやインデントの数を指定したり、ダブルクォートをシングルクォートに揃えたりと、コードのフォーマットを指定することができる。
特に複数人で開発するときにこのファイルを共有してコードフォーマットを揃えてコンフリクトを防ぐことができる。

Prettierはコードを整形するためのツール

Prettierのインストール
$ npm install prettier --save-dev

作成できたら.prettierrcというファイルを作成して、そのファイル内にコードフォーマットの設定値を記載する。

.prettierrc中身例
{
    // コードの末尾にセミコロンを入れるか
    "semi":false,
    // オブジェクト定義の最後のカンマを無しにするか
    "trailingComma":"none",
    // 文字列の定義などのクォートにシングルクォートを使用するか
    "singleQuote":true,
    // 行を開業する際の文字列の指定
    "printWidth":80
}

そのほかのオプションについては以下公式ドキュメント参考

Prettierの適応にはpackage.jsonscriptsの項目に以下を追加

package.json
{
    "scripts":{
        "prettier-format":"prettier --config .prettierrc 'src/**/*.ts' --write"
    }
}

以下のコマンドを実行することでTypeScriptのソースコードに対してフォーマットが実行される。

$ npx run prettier-format

ESLint

JavaScriptTypeScriptのコードを解析し、問題がある箇所を指摘するツール。

Prettierと併用して使うことが多い。

.eslintrc.jsというファイルで設定を記述する。

コンパイルオプション

noImplictAny

noImplictAnyは型定義がない場合コンパイルエラーを出すためのオプション

TypeScriptからJavaScriptにトランスパイルする際型定義がないとanyとして扱われる。anyはエラーの原因なので、トランスパイルする過程で定義されたanyを検出して、エラーを吐かせるようにする方がいい。

strictNullChecks

strictNullChecksは明示的にnullundefinedを指定しない場合にエラーを吐くオプション

Union型などで、nullundefinedを明示することでエラーを防げる。

target

targetオプションはどのバージョンのECMAScriptで出力するのかを指定できるオプション

ECMAScriptJavaScriptの標準規格のこと。

$ tsc --target es5 sample.ts

このようにすることでsample.tsECMAScript 5準拠のJavaScriptにトランスパイルすることができる。

1
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
1
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?