■ はじめに
最近、Pulumi で TypeScript を使ってて、 その際に、クラス / インターフェイス を使いたかったのでメモ。
目次
【0】実行環境 【1】クラス 1)アクセス修飾子 2)継承 3)抽象クラス・メソッド - abstract 4)静的メソッド (static method) 5)別ファイルに定義する 【2】インターフェイス 【3】トラブル「TypeError: Class extends value undefined is not a constructor or null」
【0】実行環境
* ブラウザで実行できる
https://www.typescriptlang.org/play
【1】クラス
// クラス定義 class Person { // プロパティ private name: string // コンストラクタ constructor(name: string) { this.name = name } // メソッド sayHello(): string { return `Hello, ${this.name}!!`; } } // 呼び出し例 const person: Person = new Person("Mike"); console.log(person.sayHello()); // Hello, Mike!!
1)アクセス修飾子
[1] private [2] protected [3] public (デフォルト)
2)継承
// extends で 継承 class Employee extends Person { constructor(id: number, name: string) { super(name) this.id = id } }
3)抽象クラス・メソッド - abstract
https://qiita.com/suema0331/items/374c0757aa00b37d98bd
使用上の注意
* abstractメソッドは、abstractクラスからしか使用できない
サンプル
abstract class BaseDeployment { abstract deploy(): void; }
4)静的メソッド (static method)
class Connection { public readonly string url1; public readonly string url2; constructor(domain: string) { this.url1 = Connection.getUrl(domain) this.url2 = Connection.getUrl(domain, 'test1', 'path2/path3') } static getUrl(domain: string, ...params: string): string { return `https://${domain}/` + params.join('/') } } const connection = new Connection('hello_world.com') // https://hello_world.com/ console.log(connection.url1) // https://hello_world.com/test1/path2/path3 console.log(connection.url2)
5)別ファイルに定義する
クラスファイル「helloWorld.ts」
// クラス定義 export class HelloWorld { readonly val: string constructor( public name: string, { val }: HelloArgs, ) { this.name = name } // メソッド sayHello(): string { return `Hello, ${this.name}!!`; } } // クラス用の引数を定義する場合 export type HelloArgs = { readonly val: string; }
呼び出し側
import { HelloWorld } from "./helloWorld" // import * as hw from "./helloWorld" const helloWorld: HelloWorld = new HelloWorld("Mike"); console.log(helloWorld.sayHello()); // Hello, Mike!!
【2】インターフェイス
interface IPerson { name: string sayHello(): string } interface IWorker { work(): void } // クラス定義 class Employee implements IWorker, IPerson { constructor(public name: string) { this.name = name } // メソッド sayHello(): string { return `Hello, ${this.name}!!`; } work() : void { console.log("Working...") } } // 呼び出し例 const employee: Employee = new Employee("Mike"); console.log(employee.sayHello()); // Hello, Mike!!
【3】トラブル「TypeError: Class extends value undefined is not a constructor or null」
以下「2)エラー発生時のソース」をコンパイルしたら エラー「TypeError: Class extends value undefined is not a constructor or null」が発生した。 (詳細は、以下の「1)エラー内容」を参照)
1)エラー内容
TypeError: Class extends value undefined is not a constructor or null at Object.<anonymous> (C:\xxxx\sub-modules\deployment.ts:3:38) at Module._compile (node:internal/modules/cjs/loader:1103:14) at Module.m._compile (C:\xxxx\node_modules\ts-node\src\index.ts:439:23) at Module._extensions..js (node:internal/modules/cjs/loader:1155:10) at Object.require.extensions.<computed> [as .ts] (C:\xxxx\node_modules\ts-node\src\index.ts:XX:12) at Module.load (node:internal/modules/cjs/loader:981:32) at Function.Module._load (node:internal/modules/cjs/loader:822:12) at Module.require (node:internal/modules/cjs/loader:1005:19) at require (node:internal/modules/cjs/helpers:102:18) at Object.<anonymous> (C:\xxxx\index.ts:X:1)
2)エラー発生時のソース
index.ts (エラー発生時)
import { Deployment } from "./sub-modules/deployment"; export abstract class BaseDeployment { name: string constructor(name: string) { this.name = name } abstract deploy(): void; } const d = new Deployment() d.deploy()
sub-modules/deployment.ts
import * as base from "../index"; //import { BaseDeployment } from "./baseDeployment"; export class Deployment extends base.BaseDeployment { constructor() { super("demo") } public deploy() { console.log(`test`) } }
3)原因
https://qiita.com/taharah/items/ef69f2b722844cc249f6
より、どうも循環しているみたい
4)解決案
ファイルを分割した。
index.ts (修正版)
import { BaseDeployment } from "./sub-modules/baseDeployment"; import { Deployment } from "./sub-modules/deployment"; const d = new Deployment() as BaseDeployment d.deploy()
./sub-modules/baseDeployment.ts (修正版・追加)
export abstract class BaseDeployment { name: string constructor(name: string) { this.name = name } abstract deploy(): void; }
./sub-modules/deployment.ts (修正版)
import { BaseDeployment } from "./baseDeployment"; export class Deployment extends BaseDeployment { constructor() { super("demo") } public deploy() { console.log(`test`) } }
参考文献
https://b1san-blog.com/post/ts/ts-class/
関連記事
TypeScript ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/12/21/180904
TypeScript ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2021/02/15/000000
TypeScript ~ export / import ~
https://dk521123.hatenablog.com/entry/2022/03/23/233512
条件分岐
https://dk521123.hatenablog.com/entry/2022/03/12/000000
可変長引数
https://dk521123.hatenablog.com/entry/2016/02/08/111250
ループ操作 ~ map etc ~
https://dk521123.hatenablog.com/entry/2021/01/03/000000
配列・リスト操作
https://dk521123.hatenablog.com/entry/2021/02/10/225119
配列・リスト操作 ~ ソート編 ~
https://dk521123.hatenablog.com/entry/2021/02/24/222452
配列・リスト操作 ~ スプレッド構文 / Three-dots ~
https://dk521123.hatenablog.com/entry/2021/03/09/000000
Enum / Union / const assertion
https://dk521123.hatenablog.com/entry/2021/03/17/005906
TypeScript ~ 型エイリアス (Type Alias) ~
https://dk521123.hatenablog.com/entry/2022/04/02/000000
Visual Studio Code ~ TypeScript ~
https://dk521123.hatenablog.com/entry/2022/03/06/000000
JavaScript ~ クラス ~
https://dk521123.hatenablog.com/entry/2015/12/12/093900