カテゴリー
JavaScript TypeScript

NW.js + Typescript で exports is not defined の対処方法

TypeScriptから生成されたJavascriptファイルには、以下が含まれます。

Object.defineProperty(exports, "__esModule", { value: true });

これが、NW.jsに読み込まれたとき、以下のエラーメッセージが出力され、Javascriptが実行できません。

Uncaught ReferenceError: exports is not defined

対処方法

HTMLファイルに以下を記述し、各Javascriptファイルが読み込まれる前に実行されるようにします。

<script>var exports = {"__esModule": true};</script>

こうすることで、exports未定義の状態にならず、実行できるようになります。

カテゴリー
TypeScript

TypeScript で、指定したディレクトリ内に存在するディレクトリやファイルのリストを取得する

TypeScriptでNodeJSを使い、指定したディレクトリ内に存在する
ディレクトリやファイルのリストを取得してみたいと思います。

ディレクトリパスの中に存在しているディレクトリを取得する

fs.readdirSync メソッドを使用してディレクトリを参照し、ディレクトリのみにフィルタリングして
リストを取得します。

import {readdirSync} from "fs"

export function getDirectoryList(dirPath:string):string[] {

    let dirList: string[] = new Array();

    dirList = readdirSync(dirPath, {
        withFileTypes: true, 
    }).filter(dirent => dirent.isDirectory())
    .map(dirent => dirent.name);

    return dirList;

}

引数にディレクトリパスを指定します。返り値として、ディレクトリ名が格納された文字列配列を返却します。

fs.readdirSync を使用して、ディレクトリ内のリストを取得します。
このとき、withFileTypes:trueをオプションで指定することにより、fs.Dirent
オブジェクトで返却されます。

Node.js fs.readdirSync

その後、dirent.isDirectory() でディレクトリだけにフィルタリングします。
このdirent.isDirectory()メソッドは、direntオブジェクトの中身がディレクトリの場合に
Trueを返却します。

Class: fs.Dirent

最後に mapメソッドでディレクトリ名を取得し、配列に格納します。

ディレクトリパスの中に存在しているファイルを取得する

基本的には、上述のgetDirectoryListメソッドと同じで、違いとしては、
フィルタリングの箇所をdirent.isDirectory() から dirent.isFile() に変更しています。

これにより、ファイルのみのリストを文字列配列として返却しています。

import {readdirSync} from "fs"

export function getFileList(dirPath:string):string[] {

    let dirList: string[] = new Array();

    dirList = readdirSync(dirPath, {
        withFileTypes: true, 
    }).filter(dirent => dirent.isFile())
    .map(dirent => dirent.name);

    return dirList;

}

カテゴリー
aws TypeScript

TypeScript で AWS DynamoDB のテーブルを作成する

TypeScript は手軽にプログラミングできて、型定義がしっかりしているから
ソースコードの自動補完もできて、本当に大好きです。

ということで、 TypeScriptを 使って AWS DynamoDB のテーブルを作成する方法を紹介します。

ソースコード

import {DynamoDB,config} from "aws-sdk"

config.update({
    region: "ap-northeast-1"
})

let param:DynamoDB.CreateTableInput = {
    TableName: "codeSnippets",
    KeySchema: [
        { AttributeName: "Key1", KeyType: "HASH"},
        { AttributeName: "Range1", KeyType: "RANGE"}
    ],
    AttributeDefinitions: [
        { AttributeName: "Key1", AttributeType: "S" },
        { AttributeName: "Range1", AttributeType: "S" }
    ], 
    ProvisionedThroughput: {
        ReadCapacityUnits: 5,
        WriteCapacityUnits: 5
    }
};

let dynaDB = new DynamoDB();

dynaDB.createTable(param, (err, data) => {
    if (err) console.log(JSON.stringify(err, null, 2));
    else console.log(JSON.stringify(data, null, 2));
})

1. NPM パッケージのインストール

aws-sdk というパッケージが必要ですので、インストールします。

npm i --save aws-sdk

2. import

import {DynamoDB,config} from "aws-sdk"

今回は、DynamoDBというクラスと、configというメソッドを使用しますので、それぞれインポートします。

3. Region の指定

config.update({
    region: "ap-northeast-1"
})

DynamoDBを使用するリージョンを指定します。
東京リージョンは ap-northeast-1 です。

他のリージョンを確認したいときは、以下のページを参照してください。

AWS のリージョンとエンドポイント

テーブル定義パラメタの作成

let param:DynamoDB.CreateTableInput = {
    TableName: "codeSnippets",
    KeySchema: [
        { AttributeName: "Key1", KeyType: "HASH"},
        { AttributeName: "Range1", KeyType: "RANGE"}
    ],
    AttributeDefinitions: [
        { AttributeName: "Key1", AttributeType: "S" },
        { AttributeName: "Range1", AttributeType: "S" }
    ], 
    ProvisionedThroughput: {
        ReadCapacityUnits: 5,
        WriteCapacityUnits: 5
    }
};

DynamoDB.CreateTableInput インタフェースを使用してパラメタを定義します。

TableName : 作成するテーブル名を指定します。

KeySchema : キーを定義します。

AttributeName でキー属性名を指定し、KeyType でキータイプを指定します。

キータイプは「ハッシュ」と「レンジ」の2種類があります。「ハッシュ」のみで構成される場合は、
キー項目は1つになり、「ハッシュ」と「レンジ」の2つで構成される場合は、それぞれ1つずつの
キー項目を指定します。

AttributeDefinitions : キー項目属性を定義します。

AttributeName はさきほどと同じ、キー項目名を指定します。

AttributeType で、データ項目を指定します。

- 文字列データの場合は「S」、数値データの場合は「N」、バイナリデータの場合は「B」を指定できます。

ProvisionedThroughput : スループットをプロビジョニングモードで指定します。

ReadCapacityUnits が読み込みキャパシティユニット、WriteCapacityUnits が書き込みキャパシティユニットです。

↓ここの公式ドキュメントに詳しく記載されています。

読み込み/書き込みキャパシティーモード

カテゴリー
TypeScript WebFrontEnd

JavSscript, TypeScript で 型のメソッドを使いたいのに TypeError: Cannot read property ‘xxxxx’ of undefined が出るときの対処方法

たとえば、オブジェクト型なのに、文字列型の substrメソッドを使いたいとき、
そのまま obj_A.substr(0,2) などとした場合、以下のエラーが発生します。


TypeError: Cannot read property 'substr' of undefined

こんなときは、文字列型として、オブジェクトを生成します。


let tmpKekkaStr:any;
tmpKekkaStr = new String(obj_A)

new String(obj_A) で文字列型オブジェクトを生成しています。

こうすることで、tmpKekkaStr は文字列型として定義されますので、

substr()substring()slice() など使うことができます。

カテゴリー
TypeScript

TypeScript でログローテーションする

TypeScript でログローテーションするプログラムを作成しましたので紹介します。

仕様

  • 引数に LogDir, LogFileName, LogRotatePrefix の3つを持ちます。
  • LogDir は、ログが保存されているディレクトリです。この中にローテーションされたログファイルも格納します。
  • LogFileName はログファイル名です。 LogDir + LogFileName でフルパスになります。
  • LogRotatePrefix はローテーションされたログファイル名の先頭に付与される文字列です。
  • ログディレクトリに保存されているログファイルを、LogRotatePrefix_YYYYMMDDHHMMSS.zip に圧縮します。
  • ログファイルの中身をクリアします。

ソースコード

import * as fs from 'fs';
import * as compressing from "compressing";

main()

function main() {
    let LogDir:string = __dirname + "/../log"
    let LogFileName:string = "app.log"
    let LogRotatePrefix:string = "app"

    LogRoate(LogDir, LogFileName, LogRotatePrefix)
}

function LogRoate(LogDir:string, LogFileName:string, LogRotatePrefix:string) {
    let RotateFileName:string = `${LogRotatePrefix}_${getNowYMD()}_${getHHMISS()}.zip`

    compressFileToZip(LogDir + "/" + LogFileName, LogDir + "/" + RotateFileName, () => {
        fs.writeFileSync(LogDir + "/" + LogFileName, "");
    })
}

function getNowYMD():string{
    let dt = new Date();
    let y:string = dt.getFullYear().toString();
    let m:string = ("00" + (dt.getMonth()+1)).slice(-2);
    let d:string = ("00" + dt.getDate()).slice(-2);
    let result:string = y + m + d;
    return result;
  }

function getHHMISS():string{

    let dt = new Date();
    let hh:string = dt.getHours().toString();
    let mi:string = dt.getMinutes().toString();
    let ss:string = dt.getSeconds().toString();

    hh = ("00" + hh).slice(-2);
    mi = ("00" + mi).slice(-2);
    ss = ("00" + ss).slice(-2);

    return hh + mi + ss;

}

export function compressFileToZip(filepath: string, zipFilePath: string, callback?: Function) {
    compressing.zip.compressFile(filepath, zipFilePath)
    .then( () => {
        if (callback) callback()
        else return 0
    })
    .catch( (e) => {
        console.log(e)
    })
}

main() 関数

main()の中で、LogDir, LogFileName, LogRotatePrefix を定義しています。

これらの引数で LogRoate() 関数を呼び出します。

LogRoate() 関数

ローテーションファイル名を定義します。ローテーションファイル名は LogRotatePrefix_YYYYMMDDHHMMSS.zip になります。

その後、compressingを用いて zip 圧縮します。

compressFileToZip() 関数

Node モジュール compressing を使用して、zip圧縮する関数です。

詳しくは、以下に記載しています。

Typescript でファイルやフォルダを圧縮する方法

圧縮が成功したら、コールバック関数で定義している fs.writeFileSync で、ログファイルの中身をクリアしています。

getNowYMD() 関数

現在日付を YYYYMMDD 形式で取得する関数です。

詳しくは、以下に記載しています。

Javascript で現在日付の YYYYMMDD 形式、現在時刻の HHMMSS 形式を取得する

getHHMISS() 関数

現在時刻を HHMMSS 形式で取得する関数です。

詳しくは、以下に記載しています。

Javascript で現在日付の YYYYMMDD 形式、現在時刻の HHMMSS 形式を取得する

カテゴリー
TypeScript

TypeScript でファイルを1行ずつ読み込んで処理する方法

NodeJS では、fs.readFileSyncなどでファイルを一括で読み込む方法はありますが、
1行ずつ読み込んで処理したかったので、やり方を記載します。

readline を使う

NodeJS の readlineを使って、以下のように書きます。

import * as fs from "fs"
import * as readline from "readline"

function ReadFileLine_SJIS(InputFilePath:string, CallBack:Function) {

    var stream = fs.createReadStream(InputFilePath);
    var reader = readline.createInterface({ input: stream });

    reader.on("line", (data:string) => {
        CallBack(data)
    });
}
  • fs.createReadStream でファイルストリームを作成します。
  • その後、readline.createInterfaceで入力インタフェースに、作成したファイルストリームをセットします。
    readline.on` メソッドで1行ずつ処理します。

onメソッド以降はコールバック関数で記載していますが、引数にとらずに直接ロジックを
記載してもいいと思います。

Readline | Node.js v12.5.0 Documentation

文字コードを シフトJIS で読み込む

文字コードをSJISで読み込む場合は、npm パッケージの iconv-lite を使用します。

iconv-lite | npm

import * as fs from "fs"
import * as readline from "readline"
var iconv = require("iconv-lite");

function ReadFileLine_SJIS(InputFilePath:string, CallBack:Function) {

    var stream = fs.createReadStream(InputFilePath).pipe(iconv.decodeStream("Shift_JIS"));
    var reader = readline.createInterface({ input: stream });

    reader.on("line", (data:string) => {
        CallBack(data)
    });
}
  • 違いは、fs.createReadStream の後ろに iconv.decodeStreamShift_IJSに変換しています。

カテゴリー
TypeScript

TypeScript で 配列変数を定義したのに、Cannot read property ‘push’ of undefined が出るときの対処方法

TypeScript で 配列変数を定義したのに、Cannot read property 'push' of undefinedエラーが表示されることがあります。

エラーになるソースコード例


let insertSQL:string[];
insertSQL.push("  INSERT  INTO  TABLE  VALUES  ('value')")

エラーメッセージ


TypeError: Cannot read property 'push' of undefined

対処方法

配列変数を宣言する際に、new Array() でArrayオブジェクトを生成します。


let insertSQL:string[] = new Array();
insertSQL.push(  INSERT  INTO  TABLE  VALUES  ('value'))

こうすると、エラーなく push が使えます。

カテゴリー
TypeScript 仕事効率化

TypeScript で バッチジョブを開発するときのボイラープレート

TypeScript で バッチジョブを開発するときのボイラープレート

TypeScript を使用していますか? 私はTypeScriptを愛用しています。理由としては、

  1. Node モジュールを使用できるためかなり効率よく開発が進むこと
  2. ソースコードの自動補完機能があること
  3. 型定義されているためソースコードが分かりやすくなること

の3点です。

この記事では、TypeScript でバッチジョブを開発するときのボイラープレートを紹介します。

このボイラープレートが提供する機能

このボイラープレートは以下の機能を提供します。

  1. src ディレクトリにソースコードを配置
  2. dist ディレクトリ にコンパイル済み js ファイルを出力
  3. tsc –watch によるソースコードの自動コンパイル
  4. @types/node のインストール

各種ファイルダウンロード

下準備1:typescript をインストールする

TypeScript のインストールが未だの場合は、インストールしましょう。


npm install -g typescript

下準備2:package.json を作成する

まず、npm init -y で package.json を作成しましょう。


D:\ts-batch-boilar>npm init -y
Wrote to D:\ts-batch-boilar\package.json:
{
  "name": "ts-batch-boilar",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

下準備3:tsconfig.json を作成する

次に、tsconfig.json を作成します。


D:\ts-batch-boilar>tsc --init
message TS6071: Successfully created a tsconfig.json file.

package.json を修正する

以下のように package.json を修正します。

  1. scripts に watch スクリプトを追加
  2. dependencies に @types/node を追加
{
  "name": "ts-batch-boilar",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "tsc -watch"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@types/node": "^12.0.4"
  }
}

tsconfig.json を修正する

以下のように tsconfig.json を修正します。

  1. outDir にコンパイル先ディレクトリを指定
  2. rootDir にソースディレクトリを指定
  3. typeRoots に Node Modules の @types を指定
  4. include にコンパイル対象ソースを指定
  5. exclude にコンパイル対象外のソースを指定
{
  "compilerOptions": {
    /* Basic Options */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    // "lib": [],                             /* Specify library files to be included in the compilation. */
    // "allowJs": true,                       /* Allow javascript files to be compiled. */
    // "checkJs": true,                       /* Report errors in .js files. */
    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    // "declaration": true,                   /* Generates corresponding '.d.ts' file. */
    // "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
    // "sourceMap": true,                     /* Generates corresponding '.map' file. */
    // "outFile": "./",                       /* Concatenate and emit output to single file. */
    "outDir": "./dist/",                        /* Redirect output structure to the directory. */
    "rootDir": "./src/",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    // "composite": true,                     /* Enable project compilation */
    // "removeComments": true,                /* Do not emit comments to output. */
    // "noEmit": true,                        /* Do not emit outputs. */
    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

    /* Strict Type-Checking Options */
    "strict": true,                           /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
    // "strictNullChecks": true,              /* Enable strict null checks. */
    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
    // "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
    // "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. */
    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
    // "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */

    /* Additional Checks */
    // "noUnusedLocals": true,                /* Report errors on unused locals. */
    // "noUnusedParameters": true,            /* Report errors on unused parameters. */
    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */

    /* Module Resolution Options */
    // "moduleResolution": "node",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
    "typeRoots": [
      "node_modules/@types"
    ],                       /* List of folders to include type definitions from. */
    "types": [
      "node"
    ],                           /* Type declaration files to be included in compilation. */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */

    /* Source Map Options */
    // "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
    // "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

    /* Experimental Options */
    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

src ディレクトリ と dist ディレクトリを作成する

src ディレクトリ と dist ディレクトリを作成します。

  • srcディレクトリは、ソースコード(tsファイル)を格納するフォルダです。
  • dist ディレクトリは、コンパイル済み js ファイルが出力されるフォルダです。

npm install で パッケージをインストールする

npm install でパッケージをインストールします。

以上

想定どおりの動作をしているか確認してみましょう。

カテゴリー
TypeScript

Typescript で開発している人は watch オプションが便利

TypeScript ソースコードはそのままでは実行できません。 tsc コマンドでコンパイルし、
Javascript コードに変換する必要があります。

しかし、コードを変更するたびに tsc コマンドを実行して、内容確認して、とやるのは
本当に面倒ですよね。

今回は、tsc の watch コマンドを使用して、ソースコードが変更されるたびに
自動的にコンパイルしてくれるような設定方法を紹介します。

1. まず、tsconfig.json ファイルを準備する

tsc --init コマンドを実行して、tsconfig.json ファイルを生成します。

この中から、outDir, rootDir, include, exclude を編集します。

  • outDir : コンパイルされた Javascript ソースコードが出力されるフォルダ
  • rootDir : TypeScript ソースコードを配置するフォルダ
  • include : コンパイルする TypeScript ソースコードに含めるファイルやフォルダ
  • exclude : コンパイルする TypeScript ソースコードに含めないファイルやフォルダ

tsconfig.json 設定例


{
  "compilerOptions": {
      ...
    "outDir": "./dist/",                        /* Redirect output structure to the directory. */
    "rootDir": "./src/",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
      ...
  },"include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

package.json で npm スクリプトに登録

npm run watch で TypeScript を自動的にコンパイルするように設定します。

tsc -w コマンドを実行しているだけです。


{
  ...
  "scripts": {
    ...
    "watch": "tsc -w"
    ...
  },
  ...
}

実行例

設定は以上ですので、実行してみます。

カテゴリー
TypeScript

TypeScript で Electron アプリを開発しているときに発生する exports is not defined エラーの対処法

Typescript を使用してElectronアプリを開発するとき、importで様々なモジュールを呼び出したいですよね。

このとき、以下のエラーが発生します。


index.js:2 Uncaught ReferenceError: exports is not defined

このときの tsc の バージョンは 3.3.4 でした。


C:\@work\app\todoTimer>tsc --version
Version 3.3.4000

対処方法

typescript でコンパイルした Javascriptソースの前に、var exports = {};を宣言します。
具体的には、html の script タグ で宣言すると各Typescriptソースコードを変更する必要がなくて簡単です。


    <script> var exports = {}; </script>
    <script type="text/javascript" src="script/index.js"></script>

無事、エラーがなくなりました。

参考にしたサイト

Uncaught ReferenceError: exports is not defined in filed generated by Typescript