Edited at

TypeScriptを初めて書いた時詰まった箇所のメモ

More than 1 year has passed since last update.

モチベーション


  • jsでも型宣言したい。

  • クラスもメンバ変数とかprivate/publicほしい。

  • なんとなく今時っぽい。

始めてみたら躓く箇所があったのと、すぐ忘れそうなことはまとめておく。


型定義ファイル

jqueryとか、そういうライブラリ使うとき型定義ファイルというやつ追加しないと

コンパイル通らない。

1.0時代はtypings?とか色々あったみたいだけど、2.0以降は@typesが良さ気。

またホームディレクトリに変な設定ファイル増えるかと思って一瞬げんなりした。

yarn add @types/*****

してから、tsconfig.jsonのtypesに追加したやつを書く

@types/ は自動解決されるようにハードコードされているので typeRoots, typesは不要という

ご指摘をいただきました。

自分の環境でテストできていないのでそのままにしておきますが、もし試される方がいましたら

参考にしてください。


tsconfig.json

{

"compilerOptions":{
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"target": "es5",
"sourceMap": true,
"allowJs": true,
"typeRoots": [
"./node_modules/@types"
],
"types" : ["greensock", "jquery", "pixi.js"]

},
"include": [
"app/**/*.ts"
],
"exclude": [
"node_modules",
"build"
]
}



基本の型と型宣言

http://qiita.com/armorik83/items/4544248ecaf6569180d6


importとか

import側


main.ts


import {Test} from './modules/Test';
import * as $ from 'jquery';

class App{

constructor(){

const test:Test = new Test();
}

}


export側


Test.ts


export class Test {

constructor() {
console.log("test constructor");

}

}



classメンバ変数/関数


main.ts

class App{

private x: number;
public y: number;

constructor(){
this.x = 10;
this.y = 20;

this.hoge();
}

private hoge(): void {
console.log("hoge");
}
}



イベントのコールバックでthisがいない

pixiでshaderをロードしようとしてコールバック関数雨のonLoadでthisがnullになって困った。

この辺みて解決。

http://stackoverflow.com/questions/20627138/typescript-this-scoping-issue-when-called-in-jquery-callback

アロー関数にするか以下に書いたような感じで分ける。

コードにするとこんなかんじ


test.ts


PIXI.loader.add('shader', '../shader/shader.frag')
.load((loader: PIXI.loaders.Loader, res:any) => this.onLoadedShader(loader, res));

~~

private onLoadedShader(loader: PIXI.loaders.Loader, res:any):void{
console.log("loaded shader");
console.log(this); //ここのthisがnullになってた。

}



連想配列

let arg: { [index: string]: string; } = {};

もしくは

interface Dictionary {

}
let arg: Dictionary = {};

key側の型はなんでも通っちゃうらしい、のと

containsKeyとかあるのかな?(未調査)

なのでDictionaryとして使うには少しコツがいりそう。


文字列Enum

下記のリンクはイベント名でstringとか型安全じゃなくて嫌だ。

みたいなはなしだと思うんですけど、イベント名とは

別用途で文字列を管理しておきたかったので、調べた。

が、最近のバージョンで使えるようになったらしい。

classをつくる方法

http://qiita.com/tonkotsuboy_com/items/b32801246ec14f444514

namespace + const

http://qiita.com/ConquestArrow/items/02826db3ddbe98d280bd

readonlyがつかえるようになったのでどっちもあんまり変わらないのではないかという印象。

Typescriptアップデート激しいのでEnum-string関連でもう少し調べてみたらこんなのもあった。

http://angularfirst.com/typescript-string-enums/

const Size = {

XLarge: 'xl' as 'xl',
Large: 'l' as 'l',
Medium: 'm' as 'm',
Small: 's' as 's'
}
type Size = (typeof Size)[keyof typeof Size];
export { Size };

上の記事でもふれてたストリングリテラル型とv2.2~ で追加された

"keyof"を利用して文字列enumをつくる方法

keyofについてはこちら

http://qiita.com/Quramy/items/e27a7756170d06bef22a

最後のやつ採用した。

ちなみに、foreachは

for(var s in Size) {

console.log(s);
}

でふつうにできた。

嘘、上記だとXLarge, Large,...ってのがでてくるので

for(let s in Size){

let value = (<any>Size)[s];
console.log(value);
}

こうする。(Size)としてあげないと

Element implicitly has an 'any' type because type~

がでる

でもstring literalって

var hoge:Size = "Hoge" as Size

ができてしまうところに少し不満を感じた。


外部モジュールクラス

クラスは全部個々のファイルにして外部モジュールをimportする感じでつくっていた。


A.ts

export class A{

constructor(){
}
}


B.ts

import {A} from '.A';

export class B{
constructor(){
const a = new A();
}
}


みたいな感じ。


C.ts

export class C{

private a:A;
constructor(arg_a:A){
this.a = A;
}
}

みたいなとき、C.tsでAが定義されてないみたいな感じで怒られる。

こういう時、index.d.tsつくって定義するもんだと思ってたんですが

(なんとなく、newしてないのにimportするのがイメージと違ったので)

自分でindex.d.ts書いてたら、どうやらimportしたモジュールと型定義ファイルの

型が被る?(説明しづらい)ようでうまくいかなかった。

大きなtsのプロジェクトどうやってるんだろと思って気になったので、

https://github.com/ReactiveX/rxjs/tree/master/src/operator

を見てみたところ、ふつうにそのファイル内で使ってるclass(依存性があるもの)は

全部importしてそうだった。


C.ts

import {A} from "./A"

export class C{
private a:A;
constructor(arg_a:A){
this.a = A;
}
}

とするのがどうやら正しそう。