モチベーション
- jsでも型宣言したい。
- クラスもメンバ変数とかprivate/publicほしい。
- なんとなく今時っぽい。
始めてみたら躓く箇所があったのと、すぐ忘れそうなことはまとめておく。
型定義ファイル
jqueryとか、そういうライブラリ使うとき型定義ファイルというやつ追加しないと
コンパイル通らない。
1.0時代はtypings?とか色々あったみたいだけど、2.0以降は@typesが良さ気。
またホームディレクトリに変な設定ファイル増えるかと思って一瞬げんなりした。
yarn add @types/*****
してから、tsconfig.jsonのtypesに追加したやつを書く
@types/ は自動解決されるようにハードコードされているので typeRoots, typesは不要という
ご指摘をいただきました。
自分の環境でテストできていないのでそのままにしておきますが、もし試される方がいましたら
参考にしてください。
{
"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"
]
}
基本の型と型宣言
importとか
import側
import {Test} from './modules/Test';
import * as $ from 'jquery';
class App{
constructor(){
const test:Test = new Test();
}
}
export側
export class Test {
constructor() {
console.log("test constructor");
}
}
classメンバ変数/関数
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になって困った。
この辺みて解決。
アロー関数にするか以下に書いたような感じで分ける。
コードにするとこんなかんじ
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 {
[index: string]: string;
}
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する感じでつくっていた。
export class A{
constructor(){
}
}
import {A} from '.A';
export class B{
constructor(){
const a = new A();
}
}
みたいな感じ。
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してそうだった。
import {A} from "./A"
export class C{
private a:A;
constructor(arg_a:A){
this.a = A;
}
}
とするのがどうやら正しそう。