2018年10月31日

TypeScript(6)模組化

前言

TypeScript的模組化大概可以分兩個部分(1)模塊(module)方式是ES6模組標準(2)命名空間(namespace)是TypeScript所制定的方法,這兩個概念會讓元件化更容易實作,在TypeScript一個*.ts檔案為一個模塊,接下來會介紹import和export這兩個語法,如何使用它們來完成模組化.

Note: TypeScript 1.5以後內部模塊稱為命名空間,外部模塊稱為模組,這是為了跟ECMAScript 2015一致.


第一部分:模塊(module)

在模組(.ts檔)定義將變數、函式和類等,外部無法存取內部邏輯,只能透過export語法去導出所需要變數、函式和類給其他模組((.ts檔)使用,當我們規劃元件時,該模組本身export的函式、變數和類就是模組的限制,這些在規劃元件藍圖時就應該考慮哪些資料需要提供給外部模組使用/不使用.在TypeScript可以支援不同的模組化系統如:AMD、SystemJS、ES Modules等等.

Export 語法

(1) export 變數

//檔名 moduleEx.ts
export var 變數名稱 = 值;
export const 變數名稱 = 值

範例:
export var kk=1234;
export const PI=3.1415 ;

(2) export 介面

//檔名 moduleEx.ts
export interface 介面 {
   //介面內容
}

範例:
export interface IShap{
    width:number;
    heigh:number; 
}

(3) export 類別

//檔名 moduleEx.ts
//方法一
export class 類別名稱 {
   //類別內容
}
//方法二
class 類別名稱 {
   //類別內容
}
export {類別名稱}

範例:
//方法一: 可以參考下面範例
//方法二
class Car{
    constructor(color:string, engine:string){
        this.color = color ; 
        this.engine = engine ; 
    }
    color:string ;
    engine:string ;

    getColor(){
        return this.color ; 
    }

    getEngine(){
        return this.engine ; 
    }
}
export {Car}

(4) export 函式

//檔名 moduleEx.ts
//方法一
export function 函式名稱 {
   //函式內容
}
//方法二
function 函式名稱 {
   //函式內容
}
export {函式名稱}

範例:
//方法一
export function sayHello(name:string){
    console.log("Hi! "+name)
}
//方法二
function sayHello(name:string){
    console.log("Hi! "+name)
}
export {sayHello}

import 語法

當我編譯有import檔案時,編譯時也會連同import的檔案.如下面moduleImport.ts有載入moduleEx.ts時也會一起編譯.

範例: tsc moduleImport.ts

import {載入名稱1,載入名稱2,...} from './TS檔案路徑'

範例://檔名 moduleImport.ts
import { kk,Car, sayHello} from './moduleEx'
console.log(kk)
let car = new Car("RED","HRV"); 
console.log(car.getColor()); 
console.log(car.getEngine());
sayHello("Jack");

範例結果

123
RED
HRV
Hi! Jack


第二部分:命名空間(namespace)

當未宣告命名空間類別都會放在global namespace中,當有相同類別名稱就會出現編譯錯誤.命名空間主要是解決1.有相同類別名稱的衝突問題.2.邏輯分類.下面這兩種寫法TypeScript仍都支援,但是官方比較建議用namespace的語法.

Internal Module Syntax (Old) 語法:

module 名稱{
     //定義類別
     class 類別名稱 {}

}

Namespace Syntax (New) 語法:

namespace 名稱{
     //定義類別
     class 類別名稱 {}

}

當開發時有兩個類別名稱都叫Account會員類別,這時編譯會有類別同名衝突的問題,但是在實務的功用卻不同一個Account用來紀錄公司內部員工的資料,另一個Account是用來處理約聘或是工讀生的資料,這是可以利用namespace分別宣告其命名空間為HR 和TEMP,很容易就可以分辨.

範例:

namespace HR{
    export class Account{
        name:string;
        salary_monthly:number;
        showSalary(){
            console.log(this.name+":月薪"+this.salary_monthly) ;
        }
    }
}

namespace TEMP{
    export class Account{
        name:string;
        salary_hourly:number;
        showSalary(){
            console.log(this.name+":時薪"+this.salary_hourly) ;
        }
    }
}

var acc01 = new HR.Account() ; 
var acc02 = new TEMP.Account() ; 
acc01.name="jack" ; 
acc01.salary_monthly=100000 ;
acc02.name="blay" ; 
acc02.salary_hourly=105;
acc01.showSalary() ;
acc02.showSalary() ; 

執行結果:

jack:月薪100000
blay:時薪105

參考

  1. 官方模塊說明
  2. tutorialspoint
  3. https://basarat.gitbooks.io/typescript/docs/tips/defaultIsBad.html
  4. 深入探討 TypeScript 之 Module

2018年10月27日

TypeScript(5) 類別

前言

JavaScript使用函式和prototype-based的方式去實現元件化,但是會造成以後維護災難的發生,日前ES6也開始加入類別的特性,但是TypeScript一開始就有以物件導向語言去做發展.我目前覺得TypeScript發展模組開發會好管理.


類別函式宣告

語法:

class 類別名稱{
    //屬性 private|public|protect 
    修飾子  屬性名稱;

    //建構子
    constructor(){
        //內容
    }

    函式名稱(參數名稱:參數類型):回傳類型{
        //內容
    }
}

說明:
private : 私人修飾子宣告讓外面無法直接存取該屬性
public : 公用修飾子讓外面可以直接存取該屬性
protect : 保護修飾子只能讓有繼承的類別可以存取該屬性

範例:類別宣告

class Person {
    private  name:string ;
    constructor(name:string){
        this.name = name
    }

    sayHi() {
        return `The person's name is ${this.name}`;
    }
}

let person = new Person('Jack');
console.log(person.sayHi()); 

輸出結果:

The person's name is Jack

繼承(Default Parameters)

TypeScript有時我們需要可以利用繼承方法來建構元件,元件的可用性更好使用.

範例:

//預設參數
class Robot extends Person{
    public talk(){
        console.log('I am a robot');
    }
}

let robot = new Robot('robot 1 ');
robot.talk() ;

輸出結果:

I am a robot

抽象(abstract)

抽象類別跟介面很像,最大部分不同地方是抽象類別只需要實作部分需告方法,如果有類別大部分方法的行為相同,但是有少部分的不同,就可以定義為抽象類別.例如:我們定義一個抽象類別為動物(Animal),所有的動物都會靠嘴巴覓食(forage)所以可以實作相同方法,走路(walk)或是跑(run)這個方法,每個動物實作的方法不同,我們可以定義成抽象函式,舉例狗是用四隻腳走路,跑也是,但是鳥走路可能是用跳;跑步可能是用飛.

範例:

abstract class Animal{
    type:string ;
    forage():void{
        console.log(this.type+"吃飯")
    }

    abstract walk(); //抽象函式
    abstract run();  //抽象函式
}

class Bird extends Animal{
    constructor(type:string){
        super();
        this.type = type;
    }

    walk() {
        console.log(this.type+"用跳的")
    }    
    run() {
        console.log(this.type+"用飛")
    }
}

class Dog extends Animal{
    constructor(type:string){
        super();
        this.type = type;
    }

    walk() {
        console.log(this.type+"用四隻腳走路")
    }    
    run() {
        console.log(this.type+"用四隻腳跑步")
    }
}
let dog = new Dog("狗");
dog.walk();
dog.run();
let bird = new Bird("鳥");
bird.walk();
bird.run();

輸出結果:

狗用四隻腳走路
狗用四隻腳跑步
鳥用跳的
鳥用飛

介面(Interface)

在typeScript的介面是一種規格,其定義屬性和方法,跟其他語言的interface
使用情境相同,通常用來定義前端元件的介面,例如表格的欄位定義成介面,可以依照不同的需求去實作表格欄位定義,這個好處是對表格欄位來說比較好維護.

範例:

interface ICar {
    color:string; //顏色
    engine:string;//引擎
    type:string;  //型號
    speed:number; //速度

    setSpeed(speed:number) ; //設定引擎速度
}

在實作介面中,TypeScript需要重新宣告屬性一次,然後實作這個介面所定義的規格.

範例:

class HRV implements ICar{
    color: string;    
    engine: string;
    type: string;
    speed: number;
    constructor( color:string, engine:string, type:string){
        this.color = color ;
        this.engine =engine;
        this.type = type ;
    }

    setSpeed(speed: number) {
        this.speed = speed;
    }
}

var hrv :ICar = new HRV("blue","SOHC 直列 4 汽缸 i-VTEC 智慧型可變汽門正時與揚程電子控制系統","一般");

hrv.setSpeed(100);
console.log(hrv.engine);
console.log(hrv.speed);

介面繼承

介面繼承又稱介面擴充,他可以像類別一樣延展介面功能,增加元件介面的可用性.由範例知道有一個介面為Shape定義基本的顏色,Square就是延伸Shape功能增加長度和寬度.

範例:

interface Shape{
    color:string;
}

interface Square extends Shape{
    width:number;
    height:number;
}

let square = {};
square.color="blue" ;
square.width=100;
square.height=10;

參考

  1. typescript class introduction
  2. https://codeday.me/bug/20170629/33692.html
  3. https://www.youtube.com/watch?v=KXc7PzE0FZM

2018年10月19日

TypeScript(3) 變數

前言

TypeScript(2) 資料型態提到string、number、boolean基本資料類型,本節我們開始講如何宣告這些變數和這些資料型態有什麼限制與用法.


聯集型別(Union Types)

當定義的變數資料型態可能會有多個資料型態,我們可以使用聯集類型語法(“|”),將不同資料類型做聯集分配.聯集型別的好處是讓我們更靈活使用資料型態指派.

語法:

//可以定義不同資料型態,使用“|”區分就可以
let myVar : string|number ;  

範例

let myVar : string|number ; 

myVar="Hello";     //編譯成功
myVar=1234;       //編譯成功
myVar=true;  // 'boolean' only refers to a type, but is being used as a value here.

//多個資料類型作聯集
let myMessage: string|number|boolean;
myMessage="Hello";
myMessage=1234;
myMessage=true;

var、let、 const##

(1) var
表示預先不知道初始值使用,預設會給undefined,

語法:

var myVar ;  

範例:

var value ;  // undefined
var data = 100; // 有明確定義初始值

範例:

function xy()
{
    var dataX = 10; // 在xy()裡面為全域變數10  

    if(true)
    {
        var dataY = 20;  

        console.log(dataX);  
        console.log(dataY); 
    }

    console.log(dataX); 
    console.log(dataY);  
}


結果:
10
20
10
20

hoisting問題:
當我一開始不用var宣吿變數時,在JavaScript執行時會將var data這行自動往上移動宣告.

範例:

function fun()
{
    dataX = 10;
    console.log(dataX);  //10
    var  dataX;
}
fun();
function fun()
{
    var  dataX;     // 移動到頂端宣告
    dataX = 10;
    console.log(dataX);  //10

}
fun();

(2) let
let會比var在scope更嚴謹的限制,let宣告的變數只會在{}內有效,這樣的好處是不容易變數使用上出現問題且也必須宣告才可以使用該變數,沒有Hosting問題.

語法:

var myVar ;  
function xy()
{
    let dataX = 10; // 在xy()裡面為全域變數10  

    if(true)
    {
        let dataY = 20;  

        console.log(dataX);  
        console.log(dataY); 
    }

    console.log(dataX); 
    console.log(dataY);  
}


結果:
10
20
10
undefined

(3) const
當宣告const在定義時必須有值且只能指派一次
語法:

const PI ;  

範例:

const PI = "3.1415"
PI="1234"     //error

Template Strings

字串的特殊用法,可以將字串內容定義變數,分別帶入

範例:

let firstName :string ="Joe" ;
let lastName :string ="Lin" ;
let  message: string = `My name is ${firstName} ${lastName}`;

console.log(message);   


結果:
My name is Joe Lin

參考

  1. unctions-rest-optional-default-params
  2. https://oomusou.io/typescript/function/

2018年10月14日

TypeScript(4) 函式

前言

TypeScript函式語法優點會對資料型態做檢查,不像JavaScript那麼自由定義,你需要宣告參數的型態和回傳參數的型態.近一步會介紹rest/optional/default params 宣告方式和使用情境.

  • JavaScript需要不需要知道函數參數資料型態,但是TypeScript有需要明確定義
  • JavaScript呼叫函式參數不需要知道參數的個數, 但是TypeScript有明確定義,並提供rest/optional/default params宣告方式

基本函式宣告

TypeScript的函式宣告必須明確定義參數的資料型態、個數以及資料型態,基本上用法跟其他程式語言一樣.

語法:

function 函式名稱(參數名稱:資料型態):回傳資料型態{
    //函式功能
}

範例:
函式宣告

let hello:string = "Hello World" ; 

//命名函式
function sayHello(message:string){
  console.log(message)
}
sayHello(hello)

//匿名函式
let anon_Hello = function(message:string):void{console.log(message)}
anon_Hello(hello);

預設參數(Default Parameters)

預設參數是當傳入 undefined 或是沒有傳入時,則會以 default parameter 取代。但是注意的地方為宣告預設參數必須在一般參數的後面,不然前面參數需要為undefined.

範例:

//預設參數
function feed(name="dog"):void{
    console.log(name);
}

feed("cat");
feed();
feed(undefined);

輸出結果:

cat
dog
dog

可選項參數(Optional Parameters)

TypeScript語法呼叫函式如果數目不正確是無法編譯,為了解決這個問題TypeScript提供optional parameters參數定義,就是你可以使用?來宣告資料型態

範例:

//可選項參數
function sayMyName(firstName:string, lastName?:string ){
    console.log(firstName+", "+lastName);
}
sayMyName("Lin");               //只傳入一個參數,編譯成功
sayMyName("Lin","Jone");      //編譯成功

輸出結果:

Lin, undefined
Lin, Jone

其餘參數(Rest Parameter)

當遇到傳入參數個數不確定時,傳統方式會使用陣列來當傳入參數;TypeScript有提供其餘參數的方式來解決傳入參數個數不確定的問題.

範例:

function sum(...values:number[] ){
    let result = 0;
    for (let val of values) {
        result += val;
    }
    return result;
}
sum();                       //編譯成功
sum(1, 2);                 //編譯成功
sum(1, 2, 3);             //編譯成功
sum(1, 2, 3, 4, 5, 6);   //編譯成功

輸出結果:

0
2
6
21

參考

  1. unctions-rest-optional-default-params
  2. https://oomusou.io/typescript/function/

2018年10月12日

TypeScript(2) 資料型態

前言

本章節介紹TypeScript的資料型態,因為TypeScript超集合(superset),所以在定義資料型態需要依照JavaScript規則.但是TypeScript提供一個強型別語法規範,在開發中大型應用上,讓JS架構在開發上或是維護上更容易找出問題.由以後的介紹可以知道TypeScript簡單來說就是將JavaScript物件化、規則化,讓他得以更好擴充、維護。

資料型態

TypeScript資料型態對應JavaScript資料型態

TypeScript JavaScript 說明 範例
boolean boolean 布林值 sex:boolean = true
number number 數值型態 total:number=100;
hex:number=0xf00d;
string string 字串型態 message:string=’今天天氣晴天’
sentence:string=這是一個句子,${message}
Array object 陣列 list:string[]=[‘a’,’b’,’c’,’d’]
Tuple boolean 類陣列但可儲存不同資料型態 item:[number,string]=[‘a’,1,’b’]
enum 定義常數 enum Color {a, b, c};
enum Color {a=1, b, c};
any var 定義變數時不預定資料型態 variable01: any = 4;
void undefined 僅儲存undefined或null值 value:void
const 定義常數 pi:const=3.1415



宣告變數語法

    變數:資料型態 = 值

範例:

   num:number=100 



斷言

Type assertions(斷言)
我們可以把斷言解釋成物件轉型,當有些物件/資料型態不同,可以透過斷言來改變物件/資料型態,但是當不能斷言,編譯器會出現錯誤訊息,

範例:

var message:any ="12345678" ;

//方法一 使用尖括弧
var message_num: number = (<**number**>message).length;

//方法二 使用 as
var message_num :number =(message as **number**);

Null 與 Undefined與NaN

Null 與 Undefined
(1) Null
通常Null在物件導向的定義均為該物件或是屬性為空並沒有指向記憶體空間.

//出現結果:Object
console.log(typeof null)

//出現結果:10
console.log(null+10)

(2) Undefined :
宣告一個變數,但卻沒有指定值,在javascript 是在給值時才決定型態,
所以預設為 undefined 未定義型態




var message
//出現結果:undefined
console.log(message)

(3)NaN
Nan是Not an Number通常會發生在數值轉換的時候,如果轉換失敗為NaN,成功就為數值




var message="HHHH"
//出現結果:NaN
console.log(parseInt(message))
// NaN在判斷式為false
if(parseInt(message)==false){
    console.log("不為數字!")
}

//用內建的isNaN()為true
if(isNaN(parseInt(message))){
    console.log("不為數字!")
}

參考資料

  1. null、undefined、NaN 的差異
  2. 了解null、undefinded、NaN

TypeScript(1) 介紹

前言

相信前端開發者對typescript不陌生,TypeScript是微軟所發展開源的程式語言,主要用來開發大型前端應用平台,由Anders Hejlsberg (C#, TurboPascal 之父)所負責發展TypeScript語言專案.

特性

我們根據Anders Hejlsberg的影片介紹大致得知TypeScript有幾種特性:

  • TypeScript是一種程式語言,讓Javascript發展有更好應用延伸
  • TypeScript是JavaScript的超集合,副檔名為.ts需要編譯成.js檔
    • 表示JS函式庫也可以被TypeScript所使用
    • TS語法也可以兼容JS語法
    • *.ts需要編譯成.js檔,才可以瀏覽器使用
  • TypeScript是opensource
  • TypeScript遵循ECMAScript 版本標準,只要是能執行這些標準的 JavaScript
    引擎都支援


環境建置

我主要是用visual studio code來開發TS專案,接下來會介紹如何安裝IDE、node.js和Typescript開發環境

(1)下載Visual Studio Code
如果不是MAC版本可以按other platforms 連結會有其他版本提供選擇(Mac, Windows,Linux(.deb, .rpm的作業系統)

(2) 下載Node.js

(3)安裝TypeScript套件
完成前兩項任務後,可以在Visual Studio Code下安裝TypeScript套件,用來開發
、編譯TS腳本.

    #> sudo npm install -g typescript

(4)編譯TS檔
以下是官方的範例,新增一個ts腳本為greeter.ts,內容如下,但是我們要使用需要把它轉成.js檔.

function sayHello(person) {
    return 'Hello, ' + person;
}
var user = 'Jack';
document.write(sayHello(user))

執行tsc指令來編譯greeter.ts檔,編譯完會產生hellow.js腳本

    > tsc greeter.ts

最後我們html將greeter.js載入,結果如下

<html>
    <body>
    </body>
    <script src="greeter.js"></script>
</html>
結果輸出:
Hello, Jack



安裝問題

Q:安裝npm套件時,出現npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules錯誤訊息
ANS:請在 npm install -g typescript加上sudo用root的權限執行安裝



參考

  1. 官方微軟介紹
    TypeScript https://blogs.msdn.microsoft.com/ericsk/2012/10/01/typescript/
  2. 官方五分鐘上手
    https://www.tslang.cn/docs/handbook/typescript-in-5-minutes.html