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 5 years have passed since last update.

TypeScript入門帳

Posted at

TypeScriptでJavaScriptを作成してみた

はじめに

TypeScript はマイクロソフトによって開発され、メンテナンスされているフリーでオープンソースのプログラミング言語である。 TypeScriptはJavaScriptに対して、省略も可能な静的型付けとクラスベースオブジェクト指向を加えた厳密なスーパーセットとなっている。
Wikipediaより

公式サイト TypeScript - JavaScript that scales.

インストール

node.jsをインストール

npm でインストール

$ node -v
v10.15.0

$ npm install -g typescript

TypeScriptファイルを作成してJavascriptにコンパイル

tsファイルでファイルを作成

main.ts
class User {

}

console.log('hello world');

tscコマンドで対象ファイルをコンパイルすると同じ階層にjsファイルが作成される

tsc main.ts
main.js
var User = (function () {
    function User() {
    }
    return User;
}());
console.log('hello world');

TypeScriptとJavaScritpの型の違い

  • TypeScript = 静的型付け言語
  • JavaScritp = 動的型付け言語

main.ts
var x: number = 10;
x = 'hello';
console.log(x);
$ tsc main.ts
main.ts:2:1 - error TS2322: Type '"hello"' is not assignable to type 'number'.
// TypeScriptは、xの型がnumberと数字で決められたため、"hello"を代入することができない
main.js
var x = 10;
x = 'hello';
console.log(x);
$ node main.js
hello
// JavaScriptは、xの型がnumberと数字と代入したあとでも、"hello"という文字へ型を変更することが可能

基本の型

let 変数名:  = ;

公式から
http://www.typescriptlang.org/docs/handbook/basic-types.html

Boolean 真偽値

let variable = true; // false

Number 数値

0-9の10進法のほかにも0-Fの16進法や小数点が可能

let number = 10;
let number = 0xf;
let number = 10.1;

String 文字

文字列

Array 配列

let list: number[] = [1, 2, 3];

Tuple

型が指定されているものに対して、配列を表現できる

let x: [string, number]; // 0番目が文字、1番目が数値
x = ['hello', 10]; // [文字,数値]なのでOK
x = [10, 'hello']; // [数値, 文字]なのでerror

Enum

列挙型

enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;
let colorName: string = Color[2];

Any

JavaScriptの動的型付け

number.ts
var x: number = 10;
x = 'hello';
console.log(x);
$ tsc number.ts //error
any.ts
var x: number = 10;
x = 'hello';
console.log(x);
$ tsc any.ts // OK

Void

anyと似ている。関数のreturnの値を決めるときに使用する

hello.ts
function hello(): void {
  console.log("Hello World !");
}
hello();
$ tsc hello.ts
$ node hello.js
Hello World !

Never

決して起こらない型らしい。never occur.
これは使用するときがいまいちわからなかった。

関数の型のオーバーロード

型が複数あった場合

main.ts
let add = function (a: any, b: any) {
    if (typeof a === 'string' && typeof b === 'string') {
        return a + ' ' + b;
    } else {
        return a + b;
    }
}

console.log(add(4, 6));
console.log(add('Hello', 'World!'));
$ tsc main.ts
$ node main.js
10
Hello World!

クラス

ECMAScript 2015からのclassにも対応している

user.ts
class User {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    hello(): void {
        console.log('Hello I\'m ' + this.name);
    }
}

let tom = new User('Tom');
console.log(tom.name);
tom.hello();
$ tsc main.ts
$ node main.js
Tom
Hello I'm Tom

アクセス修飾子(public,protected,private)

user.ts
class User {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    hello(): void {
        console.log('Hello I\'m ' + this.name);
    }
}

let tom = new User('Tom');
console.log(tom.name);
tom.hello();

これは厳密にpublicが省略されている

user.ts
class User {
    public name: string;
    constructor(name: string) {
        this.name = name;
    }
    public hello(): void {
        console.log('Hello I\'m ' + this.name);
    }
}

let tom = new User('Tom');
console.log(tom.name);
tom.hello();

privateにするとインスタンスから読みだせなくなる

user.ts
class User {
    private name: string;
    constructor(name: string) {
        this.name = name;
    }
    private hello(): void {
        console.log('Hello I\'m ' + this.name);
    }
}

let tom = new User('Tom');
console.log(tom.name);
tom.hello();
$ npx tsc main.ts
main.ts:12:17 - error TS2341: Property 'name' is private and only accessible within class 'User'.

12 console.log(tom.name);
                   ~~~~

main.ts:13:5 - error TS2341: Property 'hello' is private and only accessible within class 'User'.

13 tom.hello();
       ~~~~~


Found 2 errors.
// こうなってアクセスできませんとエラーが表示される

privateから値を取得、セットするときはgetとsetを使用する

main.ts
class User {
    private _name: string;
    constructor(_name: string) {
        this._name = _name;
    }
    public hello(): void {
        console.log('Hello I\'m ' + this._name);
    }
    get name() {
        return this._name;
    }
    set name(newValue: string) {
        this._name = newValue;
    }
}

let tom = new User('Tom');
console.log(tom.name);
tom.hello();

$ npx tsc main.ts -t es5 // オプションでes5を指定する
$ node main.js
Tom
Hello I'm Tom

Interface(オブジェクトへ型付け)

オブジェクトの型付け

main.ts
function getTotal(result: { a: number, b: number }) {
    return result.a + result.b;
}
let result = {
    a: 32,
    b: 58
}
console.log(getTotal(result));
$ npx tsc main.ts -t es6
$ node main.js
90

このgetTotalのオブジェクトプロパティを分離する

main.ts
// 分離にinterfaceを使用する
interface Result {
    a: number,
    b: number
}

function getTotal(result: Result) {
    return result.a + result.b;
}
let result = {
    a: 32,
    b: 58
}
console.log(getTotal(result));
$ npx tsc main.ts -t es6
$ node main.js
90

継承

main.ts
// 分離にinterfaceを使用する
interface Result {
    a: number,
    b: number
}

// interfaceはextendsを使い継承することが可能
interface ResultA {
    a: number
}
interface ResultB extends ResultA {
    b: number
}
function getTotal(result: ResultB) {
    return result.a + result.b;
}

classの組み合わせ

main.ts
interface Test {
    result: number;
    showResult(): void;
}

// implements interface名とすることでclassには必ずinterfaceの値を含んでいないいけないとすることができる
class User implements Test {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    hello(): void {
        console.log('Hello I\m ' + this.name);
    }
}
$ npx tsc main.ts -t es6
main.ts:6:7 - error TS2420: Class 'User' incorrectly implements interface 'Test'.
  Type 'User' is missing the following properties from type 'Test': result, showResult

6 class User implements Test {
        ~~~~


Found 1 error.

内部モジュール

main.ts
module UserModule {
    export let name = 'Tom';// 出力する際はexportをつける
    export module ResultModule {
        export let result = '80';
    }
}
console.log('I\'m ' + UserModule.name)
console.log('Result ' + UserModule.ResultModule.result)
$ npx tsc main.ts -t es6
$ node main.js
I'm Tom
Result 80

moduleを別ファイルに分ける

user.ts
module UserModule {
    export let name = 'Tom';
    export module ResultModule {
        export let result = '80';
    }
}
main.ts
/// <reference path='./user.ts' /> // /が3つと<reference />でmoduleファイルを指定する

console.log('I\'m ' + UserModule.name)
console.log('Result ' + UserModule.ResultModule.result)
tsc main.ts
node main.js
// これだとmain.tsのみがコンパイルされmoduleのファイルがコンパイルされない
tsc main.ts --out all.js // outオプションを付与して別ファイルにmain.tsとuser.tsを合わせたファイルをコンパイルする
node all.js
I'm Tom
Result 80

外部モジュール

user.ts
export let name = 'Tom';
result.ts
export let result = '80';
main.ts
import User = require('./user');
import Result = require('./result');

console.log('I\'m ' + User.name)
console.log('Result ' + Result.result)

これでmain.tsをコンパイルすればよいが方法はいくつかある
今回はNode - CommonJS

$ npx tsc main.ts -m commonjs
$ node main.js
I'm Tom
Result 80

JSはこんな感じで出力される

main.js
"use strict";
exports.__esModule = true;
var User = require("./user");
var Result = require("./result");
console.log('I\'m ' + User.name);
console.log('Result ' + Result.result);
user.js
"use strict";
exports.__esModule = true;
exports.name = 'Tom';
result.js
"use strict";
exports.__esModule = true;
exports.result = '80';

感じたこと

型がきっちりきめないといけなく、それが戸惑うところ
正直jQueryでJavaScriptを数百行単位で開発していたころに比べ、さらにJavaScriptの開発を大掛かりにしてくるととても重要になってくると感じた
JavaScriptを大規模開発で使用を前提として考えているのも納得
(sassが出始めてときもこんな感じだったのかと思う)

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?