顯示具有 typescript 標籤的文章。 顯示所有文章
顯示具有 typescript 標籤的文章。 顯示所有文章

2021/08/05

Array Object In Angular

angular 使用了 typescript,強型別是 ts 大殺器之一,除了簡單的 string、number 那些定義以外,array object 使用度也很高,最常見的作法如下。

interface Member {
    username: string;
    password: string;
}

const members: Member[] = [
    {
        username: 'chan',
        password: '123456'
    }
];

console.log(members);

這樣做沒什麼大問題,但設計上我覺得有點卡,因為 interface Member 就是一個單一物件,另一種寫法比較囉唆一點,但我覺得比較好:

interface Member {
    username: string;
    password: string;
}

interface Members extends Array<Member> {}

const members: Members = [
    {
        username: 'chan',
        password: '123456'
    }
];

console.log(members);

這樣調用 Members 時很明確就是要用陣列,而 Member 則可以給 member detail 使用,職責比較清楚,detail 理論上應該是最小單位,但如果 list 部分有自己的需求也可以自行擴充,type alias 也有相同的作法:

type Member = {
    username: string;
    password: string;
}

type Members = Member[];

const members: Members = [
    {
        username: 'chan',
        password: '123456'
    }
];

console.log(members);

2021/07/27

Specific String On Typescript

今天在寫 anguar 的時候想到一個問題,一般我們在 parameter 後面帶的會是型別,像是:

const tester = (params: { name: string }): void => {
    console.log(params.name);
}

tester({name: 'a'}); // a

那是否可以直接限定想要的內容,答案是可以的:

const tester = (params: { name: 'a' | 'b' }): void => {
    console.log(params.name);
}
  
tester({name: 'a'}); // a

此時如果你下 tester({name: 'c'}); 會得到 TS2322: Type '"c"' is not assignable to type '"a" | "b"'. 的警告,不過多寫了幾個案例以後發現一個雷,不能用變數帶入:

const tester = (params: { name: 'a' | 'b' }): void => {
    console.log(params.name);
}
const params = {
    name: 'a'
};

tester(params); // a

上方的寫法會得到警告 TS2345: Argument of type '{ name: string; }' is not assignable to parameter of type '{ name: "a" | "b"; }'. Types of property 'name' are incompatible. Type 'string' is not assignable to type '"a" | "b"'.,最簡單的解法是:

const tester = (params: { name: 'a' | 'b' }): void => {  
    console.log(params.name);
}
const params = {
    name: 'a' as const
};

tester(params); // a

不過上社群討論後,最好的解法應該是用 enum:

enum TesterParam {
    A = 'a',
    B = 'b'
}

const tester = (params: { name: TesterParam }): void => {
    console.log(params.name);
}
const params = {
    name: TesterParam.A
};

tester(params); // a

這樣的架構對維護來說是最好的。

2021/02/01

Work With Typescript And Webpack And Route

呈上個文章,如果我們想有類似 SPA 那種 routes 的功能,讓重複資源如 jQuery 統一一包該怎麼實做。

目錄結構

|   a.html
|   b.html
|   tsconfig.json
|   webpack.config.js
+---app
|
\---src
    |   main.ts
    |   routes.ts
    \---class
            a.ts
            b.ts
            main.interface.ts

我把 index.ts 改成了 main.ts,增加了,程式碼內容如下:

a.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Typescript + Webpack</title>
    <script src="app/main.js"></script>
</head>
<body id="a">
    <div id="content"></div>
</body>
</html>
b.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Typescript + Webpack</title>
    <script src="app/main.js"></script>
</head>
<body id="b">
    <div id="content"></div>
</body>
</html>
main.ts
import $ from 'jquery';
import { routes } from './routes';

$(function () {
    const classLoader = async (routeName: string): Promise<any> => {
        const imported = await import('./class/' + routeName);
        const className = routeName.toUpperCase();

        return new imported[className]();
    }

    routes.forEach(route => {
        if ($(`body#${route}`).is('*')) {
            classLoader(route).then(target => target.init());

            return false;
        }
    });
});
routes.ts
export const routes: string[] = [
    'a',
    'b'
]
webpack.config.js
const path = require('path');

module.exports = {
    mode: 'development',
    entry: {
        main: {import: './src/main.ts'}
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/,
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js'],
    },
    output: {
        path: path.resolve(__dirname, 'app'),
    },
};
main.interface.ts
export interface mainInterface {
    init(): void
}
a.ts
import { mainInterface } from './main.interface';
import $ from 'jquery';

export class A implements mainInterface {
    init(): void {
        $('div#content').html('a');
    }
}
b.ts
import { mainInterface } from './main.interface';
import $ from 'jquery';

export class B implements mainInterface {
    init(): void {
        $('div#content').html('b');
    }
}

N.html 對應 N.ts,將所有要對應的 class 設定加到 routes.ts,main.ts 會動態偵測到 html 檔案的 body 有沒有相對應的 id,有的話就去撈相對應的 class,而相對應的 class 繼承 interface 一定要有 init() 這個 method,最為這個頁面時要做的預設事件,這樣 compile 的結果 jQuery 或其他的套件只會有一份,並且做到隔離不同頁面所需要的功能。

2021/01/29

Work With Typescript And Webpack

因為工作的關係接觸了 angular,所以學習了 typescript,覺得這工具很好用,於是希望在非 angular 的環境下寫 js 時也用 typescript,這時要借用 webpack 幫忙打包成 browser 可以使用的內容。

目錄結構

├─app
└─src
    │  index.ts
    │
    └─class
            chan.ts
│  index.html
│  tsconfig.json
│  webpack.config.js

config

tsconfig.json
{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "noImplicitAny": true,
    "module": "es6",
    "target": "es5",
    "allowJs": true
  }
}

typescript 的基礎配置

webpack.config.js
const path = require('path');

module.exports = {
    mode: 'development',
    entry: {
        index: {import: './src/index.ts'}
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/,
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js'],
    },
    output: {
        path: path.resolve(__dirname, 'app'),
    },
};

webpack 的配置,會掃描 entry 我指定的檔案輸出到 app 同樣的檔名,用非 spa 的方式開發往往還是不同頁面使用不同的 js,所以這個架構對 user 並不能節省資源,因為每個 js 都會包一份 jquery,只是對開發者方便的工具而已,除非你有把握把程式寫到每個頁面隔離不互相干擾,那就可以一支檔案打天下,也是 spa 的運作方式。

npm i --save webpack webpack-cli typescript ts-loader

安裝 compiler 需要的工具

使用方式

npm i -s jquery dayjs
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Typescript + Webpack</title>
    <script src="app/index.js"></script>
</head>
<body>
    <div id="content"></div>
</body>
</html>
index.ts
import $ from 'jquery';
import { Chan } from './class/chan';

$(function () {
    const chan = new Chan();

    $('div#content').html(chan.getNow());
});
chan.ts
import dayjs from 'dayjs';

export class Chan {
    public getNow(): string {
        return dayjs().toString();
    }
}

使用 webpack compiler 之後我們頁面上的 div#content 會出現 Fri, 29 Jan 2021 09:09:52 GMT,大功告成。