[A-00194] Typescript入門
typescript入門用の記事です。
主にdeno,bunを使って実行します。
brew install denobrew install oven-sh/bun/bun適当なプロジェクトを作成します。
mkdir ts-project
cd ts-project
deno initmkdir ts-project
cd ts-project
bun init・Helloworldしてみる
console.log("Hello,typescript!");下記のコマンドで実行します。
deno run hello.ts $ deno run hello.ts 
Hello,typescript!・クラスを作ってみる
次はクラスを作ってみます。ディレクトリ構成は下記の通りです。

personクラスを作成します。
export class Person {
    name: string;
    age: number;
    address: string;
    constructor(name: string, age: number, address: string) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    private sayName(): void {
        console.log("My name is " + this.name + "!");
    }
    public getName(): string {
        this.sayName();
        return this.name;
    }
}次に実行するプログラムを書きます。
import { Person } from './clsdir/person.ts'
const p1 = new Person('takeshi', 14, 'tokyo');
var name:string = p1.getName();
console.log("His name is " + name + ".");実行すると下記にようになります。
$ deno run main.ts 
My name is takeshi!
His name is takeshi.・インターフェースを作ってみる
先ほど作成したPersonをインターフェースにしてBusinessPersonクラスを実装してみます。
export interface Person {
    getName():string;
    getAge():number;
    getAddress():string;
    getCountry():string;
}import { Person } from './person.ts';
export class BusinessPerson implements Person {
    private name: string;
    private age: number;
    protected address: string;
    private country: string;
    private job: string;
    public constructor(name:string, age:number,
        address:string, country:string, job:string) {
        this.name = name;
        this.age = age;
        this.address = address;
        this.country = country;
        this.job = job;
    }
    public introduce(): void {
        console.log("Nice to meet you.");
        console.log("My name is " + this.name +  ". I'm " + this.age + " years old.");
        console.log("I'm now live in " + this.country + ", at " + this.address + ". ");
        console.log("I'm work as " + this.job);
    } 
    public getName(): string {
        return this.name;
    }
    public getAge(): number {
        return this.age;
    }
    public getAddress(): string {
        return this.address;
    }
    public getCountry(): string {
        return this.country;
    }
}下記が実行プログラムです。
import { BusinessPerson } from './clsdir/business_person.ts'
const bp1 = new BusinessPerson("takeshi", 14 , "tokyo", "Japan", "student");
bp1.introduce();
$ deno run main.ts 
Nice to meet you.
My name is takeshi. I'm 14 years old.
I'm now live in Japan, at tokyo. 
I'm work as student・Promiseの試しに動かしてみる
promiseとは非同期処理などに使用する関数です。初心者なのでそれだけしか分かりませんが、こいつの中身がどうなっているかを調べるため、下記のコードを実行してみます。
// Promiseの中身
console.log(new Promise(() => {}));
// 成功の場合
console.log(new Promise((resolve, reject) => resolve("Success.")));
// 失敗の場合
console.log(new Promise((resolve, reject) => reject("Failed.")));
// 成功の場合
console.log(new Promise((resolve, reject) => resolve("Success.")).then((text) => console.log( text + "I'm happy.")));
// 失敗の場合
console.log(new Promise((resolve, reject) => reject("Failed.")).catch((text) => console.log( text + "I'm bored.")));user@usernoMBP test-vite1 % bun run test_main.tsx 
Promise { <pending> }
Promise { <resolved> }
Promise { <rejected> }
Promise { <pending> }
Promise { <pending> }
Success.I'm happy.
Failed.I'm bored.
error: Failed.・BunでReactを動かす
bunを使ってReactを動かす方法をメモ
bun add reactbun create react-app react-test-appcd react-test-app
bun start・TypescriptのReatチュートリアルをやってみる。
TS公式サイトにてReactのチュートリアルがあったのでそれをやってみます。Bunを使用する都合でViteでやってみます。
https://typescriptbook.jp/tutorials/react-like-button-tutorial
bun create vite test-vite1
> React
> Typescriptcd test-vite1
bun installviteプロジェクトが作成できたら下記のコマンドで動作検証します。
bun run devvite+Reactの画面が表示されたらOKです。
src配下のApp.tsxを変更します。
import React, { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
function LikeButton() {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount(count + 1);
  };
  return ( 
  <span className='likeButton' onClick={handleClick}>
    ❤️ {count}
    </span>
  );
}
function App() {
  const [count, setCount] = useState(0)
  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <div className='App'>
        <header className='App-header'>Typescriptはいいぞ</header>
        <br />
        <LikeButton />
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  )
}
export default App実行すると下記のように表示されます。

・Design Patternを学ぶ
typescriptでデザインパターンを学習します。
・FactoryMethod
abstract class Creator {
    
    public abstract factoryMethod(): Product;
    public someOperation(): string {
        const product = this.factoryMethod();
        return `Creator: The same creator's code has just worked with ${product.operation()}`;
    }
}
class ConcreteCreator1 extends Creator {
    public factoryMethod(): Product {
        return new ConcreteProduct1();
    }
}
class ConcreteCreator2 extends Creator {
    public factoryMethod(): Product {
        return new ConcreteProduct2();
    }
}
// Interface
interface Product {
    operation(): string;
}
// ConcreteClass of Product
class ConcreteProduct1 implements Product {
    public operation(): string {
        return 'This is first your product.';
    }
}
// ConcreteClass of Product
class ConcreteProduct2 implements Product {
    public operation(): string {
        return 'This is 2nd your product.'
    }
}
function clientCodeFactoryMethod(creator: Creator) {
    console.log('Client: I\'m not aware of the creator\'s class, but it still works.');
    console.log(creator.someOperation());
}
console.log('App: Launched with the ConcreteCreator1.');
clientCodeFactoryMethod(new ConcreteCreator1());
console.log('');
console.log('App: Launched with the ConcreteCreator2.');
clientCodeFactoryMethod(new ConcreteCreator2());user@usernoMBP ts-catalog % deno factory_method.ts 
App: Launched with the ConcreteCreator1.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with This is first your product.
App: Launched with the ConcreteCreator2.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with This is 2nd your product.・Prototype
class Prototype {
    public primitive: any;
    public component: object;
    public circularReference: ComponentWithBackReference;
    public clone(): this {
        const clone = Object.create(this);
        clone.component = Object.create(this.component);
        clone.circularReference = {
            ...this.circularReference,
            prototype: {...this},
        };
        return clone;
    }
}
class ComponentWithBackReference {
    public prototype;
    constructor(prototype: Prototype) {
        this.prototype = prototype;
    }
}
function clientCodeProtoType() {
    const p1 = new Prototype();
    p1.primitive = 245;
    p1.component = new Date();
    p1.circularReference = new ComponentWithBackReference(p1);
    const p2 = p1.clone();
    if (p1.primitive === p2.primitive) {
        console.log('Primitive field values have been carried over to a clone. Yay!');
    } else {
        console.log('Primitive field values have not been copied. Booo!');
    }
    if (p1.component === p2.component) {
        console.log('Simple component has not been cloned. Booo!');
    } else {
        console.log('Simple component has been cloned. Yay!');
    }
    if (p1.circularReference === p2.circularReference) {
        console.log('Component with back reference has not been cloned. Booo!');
    } else {
        console.log('Component with back reference has been cloned. Yay!');
    }
    if ( p1.circularReference.prototype === p2.circularReference.prototype) {
        console.log('Component with back reference is linked to original object. Booo!');
    } else {
        console.log('Component with back reference is linked to the clone. Yay!');
    }
}
clientCodeProtoType();user@usernoMBP ts-catalog % deno prototype.ts 
Primitive field values have been carried over to a clone. Yay!
Simple component has been cloned. Yay!
Component with back reference has been cloned. Yay!
Component with back reference is linked to the clone. Yay!・Singleton
class Singleton {
    static #instance: Singleton;
    static #value: string;
    private constructor() {}
    public static get instance(): Singleton {
        if (!Singleton.#instance) {
            Singleton.#instance = new Singleton();
        }
        return Singleton.#instance;
    }
    public setHello(value: string) {
        Singleton.#value = value;
    }
    public sayHello(): string {
        return Singleton.#value;
    }
}
function clientCodeSingleton() {
    const s1 = Singleton.instance;
    const s2 = Singleton.instance;
    s1.setHello("Guten morgen");
    if (s1 === s2) {
        console.log(
            'Singleton works, both variables contain the same instance.'
        );
        console.log('s1 is ' + s1.sayHello());
        console.log('s2 is ' + s2.sayHello());
    } else {
        console.log('Singleton failed, variables contain different instances.');
    }
}
clientCodeSingleton();user@usernoMBP src % bun singleton.ts 
Singleton works, both variables contain the same instance.
s1 is Guten morgen
s2 is Guten morgen・Appendix
参考文献はこちら
https://qiita.com/nogson/items/86b47ee6947f505f6a7b
https://qiita.com/Tsuyoshi84/items/e74109e2ccc0f4e625aa
https://qiita.com/tatsumin0206/items/5835a64cb32ace41e0b1
https://qiita.com/kushidangoAnne/items/85c147aa694e4e6cc008
https://qiita.com/yukiji/items/3db06601ece7f080b0d0
https://zenn.dev/estra/books/ts-the-minimum/viewer/2-tsmini-start-deno-ts
https://hono.dev/getting-started/basic
https://www.freecodecamp.org/news/learn-typescript-beginners-guide
https://docs.deno.com/runtime/reference/cli/init
https://refactoring.guru/ja/design-patterns/factory-method/typescript/example
https://zenn.dev/kotopasi/articles/7a623823e325b8
https://typescriptbook.jp/tutorials/react-like-button-tutorial
https://zenn.dev/ak/articles/c21609fd3b0fdc
https://zenn.dev/ak/articles/00616eb99523c2
https://zenn.dev/ak/articles/dc23436b241a84
コメントを残す