TypeScript 是什么
TypeScript 是一種由微軟開發(fā)的自由和開源的編程語言。它是 JavaScript 的一個超集,而且本質(zhì)上向這個語言添加了可選的靜態(tài)類型和基于類的面向?qū)ο缶幊獭?br> TypeScript 擴展了 JavaScript 的句法,所以任何現(xiàn)有的 JavaScript 程序可以不加改變的在 TypeScript 下工作。TypeScript 是為大型應(yīng)用之開發(fā)而設(shè)計,而編譯時它產(chǎn)生 JavaScript 以確保兼容性。

安裝 TypeScript
$ npm install -g typescript
編譯 TypeScript 文件
$ tsc app.ts # app.ts => app.js
TypeScript 數(shù)據(jù)類型
Boolean 類型
let isDone: boolean = false; // tsc => var isDone = false;
Number 類型
let count: number = 10; // tsc => var count = 10
String 類型
let name: string = 'Semliker'; // tsc => var name = 'Semlinker'
Array 類型
let list: number[] = [1,2,3]; // tsc => var list = [1,2,3];
let list: Array<number> = [1,2,3];
// tsc => var list = [1,2,3];
Enum 類型
enum Direction {
NORTH,
SOUTH,
EAST,
WEST
};
let dir: Direction = Direction.NORTH;
Any (動態(tài)類型)
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false;
=> tsc =>
var notSure = 4;
notSure = "maybe a string instead";
notSure = false;
Void
某種程度上來說,void 類型像是與 any 類型相反,它表示沒有任何類型。當(dāng)一個函數(shù)沒有返回值時,你通常會見到其返回值類型是 void:
// 聲明函數(shù)返回值為void
function warnUser(): void {
console.log("This is my warning message");
}
=> tsc =>
function warnUser() {
console.log("This is my warning message");
}
需要注意的是,聲明一個 void 類型的變量沒有什么作用,因為它的值只能為 undefined 或 null:
let unusable: void = undefined;
Tuple
元組類型允許表示一個已知元素數(shù)量和類型的數(shù)組,各元素的類型不必相同。比如,你可以定義一對值分別為 string 和 number 類型的元組。
let x: [string, number];
x = ['semlinker', 10]; // 正常賦值
x = [10, 'semlinker']; // 類型不匹配
當(dāng)訪問一個已知索引的元素,會得到正確的類型:
console.log(x[0].substr(1)); // OK
// Error, 'number' does not have 'substr' method
console.log(x[1].substr(1));
當(dāng)訪問一個越界的元素,會使用聯(lián)合類型替代:
x[3] = 'world'; // OK, 字符串可以賦值給(string | number) 類型
console.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString 方法
x[6] = true; // Error, 布爾不是(string | number) 類型
TypeScript Assertion
有時候你會遇到這樣的情況,你會比 TypeScript 更了解某個值的詳細信息。通常這會發(fā)生在你清楚地知道一個實體具有比它現(xiàn)有類型更確切的類型。
通過類型斷言這種方式可以告訴編譯器,"相信我,我知道自己在干什么"。類型斷言好比其他語言里的類型轉(zhuǎn)換,但是不進行特殊的數(shù)據(jù)檢查和解構(gòu)。它沒有運行時的影響,只是在編譯階段起作用。
類型斷言有兩種形式:
- "尖括號"語法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
- as 語法
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
TypeScript Union Types and Type Aliases
Union Types
let greet = (message: string | string[]) => {
if(message instanceof Array) {
let messages = "";
message.forEach((msg) => {
messages += ` ${msg}`;
});
console.log("Received messages ", messages);
} else {
console.log("Received message = ", message);
}
};
greet('semlinker');
greet(['Hello', 'Angular']);
Type Aliases
type Message = string | string[];
let greet = (message: Message) => {
// ...
};
TypeScript Function
TypeScript 函數(shù)與 JavaScript 函數(shù)的區(qū)別
| TypeScript | JavaScript |
|---|---|
| Types | No types |
| Arrow function | Arrow function (ES2015) |
| Function types | No Function types |
| Required and Optional parameters | All parameters are optional |
| Default parameters | Default parameters |
| Rest parameters | Rest parameters |
| Overloaded function | No overloaded functions |
箭頭函數(shù)
- 常見語法
myBooks.forEach(() => console.log('Done reading'));
myBooks.forEach(title => console.log(title));
myBooks.forEach((title, idx, arr) =>
console.log(idx + '-' + title);
);
myBooks.forEach((title, idx, arr) => {
console.log(idx + '-' + title);
});
- 使用示例
// 未使用箭頭函數(shù)
function Book() {
let self = this;
self.publishDate = 2016;
setInterval(function() {
console.log(self.publishDate);
}, 1000);
}
// 使用箭頭函數(shù)
function Book() {
this.publishDate = 2016;
setInterval(() => {
console.log(this.publishDate);
}, 1000);
}
參數(shù)類型和返回類型
function createUserId(name: string, id: number): string {
return name + id;
}
函數(shù)類型
let IdGenerator: (chars: string, nums: number) => string;
function createUserId(name: string, id: number): string {
return name + id;
}
IdGenerator = createUserId;
可選參數(shù)及默認參數(shù)
// 可選參數(shù)
function createUserId(name: string, age?: number,
id: number): string {
return name + id;
}
// 默認參數(shù)
function createUserId(name: string = 'Semlinker', age?: number,
id: number): string {
return name + id;
}
剩余參數(shù)
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
push(a, 1, 2, 3);
TypeScript Array
數(shù)組解構(gòu)
let x: number, let y: number ,let z: number;
let five_array = [0,1,2,3,4];
[x,y,z] = five_array;
數(shù)組展開運算符
let two_array = [0,1];
let five_array = [...two_array,2,3,4];
數(shù)組循環(huán)
let colors: string[] = ["red", "green", "blue"];
for(let i in colors) {
console.log(i);
}
TypeScript Object
對象解構(gòu)
let person = {
name: 'Semlinker',
gender: 'male'
};
let {name, gender} = person;
對象展開運算符
let person = {
name: 'Semlinker',
gender: 'male',
address: 'Xiamen'
};
// 組裝對象
let personWithAge = {...person, age: 31};
// 獲取除了某些項外的其它項
let {name, ...rest} = person;
TypeScript Interface
在面向?qū)ο笳Z言中,接口(Interfaces)是一個很重要的概念,它是對行為的抽象,而具體如何行動需要由類(classes)去實現(xiàn)(implements)。
TypeScript 中的接口是一個非常靈活的概念,除了可用于對類的一部分行為進行抽象以外,也常用于對「對象的形狀(Shape)」進行描述。
對象的形狀
interface Person {
name: string;
age: number;
}
let semlinker: Person = {
name: 'Semlinker',
age: 31
};
可選 | 只讀屬性
interface Person {
readonly name: string;
age?: number;
}
TypeScript Class
在面向?qū)ο笳Z言中,類是一種面向?qū)ο笥嬎銠C編程語言的構(gòu)造,是創(chuàng)建對象的藍圖,描述了所創(chuàng)建的對象共同的屬性和方法。
在 TypeScript 中,我們可以通過 Class 關(guān)鍵字來定義一個類:
class Greeter {
static cname: string = 'Greeter'; // 靜態(tài)屬性
greeting: string; // 成員屬行
constructor(message: string) { // 構(gòu)造函數(shù) - 執(zhí)行初始化操作
this.greeting = message;
}
static getClassName() { // 靜態(tài)方法
return 'Class name is Greeter';
}
greet() { // 成員方法
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
TypeScript Accessors
在 TypeScript 中,我們可以通過 getter 和 setter 方法來實現(xiàn)數(shù)據(jù)的封裝和有效性校驗,防止出現(xiàn)異常數(shù)據(jù)。
let passcode = "hello angular 5";
class Employee {
private _fullName: string;
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (passcode && passcode == "hello angular 5") {
this._fullName = newName;
}
else {
console.log("Error: Unauthorized update of employee!");
}
}
}
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
console.log(employee.fullName);
}
TypeScript Inheritance
繼承 (Inheritance) 是一種聯(lián)結(jié)類與類的層次模型。指的是一個類 (稱為子類、子接口) 繼承另外的一個類 (稱為父類、父接口) 的功能,并可以增加它自己的新功能的能力,繼承是類與類或者接口與接口之間最常見的關(guān)系;繼承是一種 is-a 關(guān)系。
在 TypeScripe 中,我們可以通過 extends 關(guān)鍵字來實現(xiàn)繼承:
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Snake extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 5) {
console.log("Slithering...");
super.move(distanceInMeters);
}
}
let sam = new Snake("Sammy the Python");
sam.move();
TypeScript Generics
泛型(Generics)是允許同一個函數(shù)接受不同類型參數(shù)的一種模板。相比于使用 any 類型,使用泛型來創(chuàng)建可復(fù)用的組件要更好,因為泛型會保留參數(shù)類型。
泛型接口
interface GenericIdentityFn<T> {
(arg: T): T;
}
泛型類
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
使用示例
interface Hero { // Hero 接口
id: number;
name: string;
}
getHeroes(): Observable<Hero[]> {
return Observable.of([
{ id: 1, name: 'Windstorm' },
{ id: 13, name: 'Bombasto' },
{ id: 15, name: 'Magneta' },
{ id: 20, name: 'Tornado' }
]);
}
上面 getHeroes(): Observable<Hero[]> 表示調(diào)用 getHeroes() 方法后返回的是一個 Observable 對象,<Hero[]> 用于表示該 Observable 對象的觀察者,將會收到的數(shù)據(jù)類型。示例中表示將會返回 <Hero[]> 英雄列表。
tsconfig.json 簡介
tsconfig.json 的作用
- 用于標(biāo)識 TypeScript 項目的根路徑
- 用于配置 TypeScript 編譯器
- 用于指定編譯的文件
tsconfig.json 重要字段
- files - 設(shè)置要編譯的文件的名稱
- include - 設(shè)置需要進行編譯的文件,支持路徑模式匹配
- exclude - 設(shè)置無需進行編譯的文件,支持路徑模式匹配
- compilerOptions - 設(shè)置與編譯流程相關(guān)的選項
tsconfig.json - compilerOptions
| 字段 | 說明 |
|---|---|
| target | Desired ECMAScript version (es3,es5,es2015,es2016,es2017, or esNext) |
| rootDir | Root directory of input files |
| listFiles | Print file names processed by the compiler |
| outDir | Directory to contain compiled results |
| outFile | File to contain concatenated results |
| watch | Watch input files |
| removeComments | Remove comments from generated output |
| noLib | Don't include the main library, lib.d.ts, in the compilation process |
| alwaysStrict | Specifies whether strict mode should be enabled |
| noEmitOnError | Don't generate output if any errors were encounted |
| noImplicitThis | Raise an error on this expressions with implied any type |
| noUnuseLocals | Report errors on unused parameters |
| noImplicitAny | Print a warning for every variable that isn't explicitly declared |
| suppressImplicit Any IndexErrors | Suppress Implicit AnyIndexError |
| skipLibCheck | Suppress type checking of declarations files |
| experimental Decorators | Enable support for ES7 decorators |
| declaration | Generate declaration file(*.d.ts) for the TypeScript code |
| declarationDir | Place declaration files in the given directory |
| module | The formate of the generated module (commonjs, amd, system, umd, or es2015) |
| noEmitHelpers | Do not insert custom helper functions in generated output |
| emitDecoratorMetadata | Insert metadata for TypeScript decorations |
| isolatedModule | Always insert imports for unresolved files |
| jsx | Generate JSC code (preserve or react) |
| moduleResolution | Strategy for resolving module (node or classic) |
tsconfig.json 示例
{
"files": ["src/app/app.ts"],
"compilerOptions": {
"target": "es5",
"removeComments": true,
"alwaysStrict": true,
"noEmitOnError": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}
}
- alwaysStrict - ES 5 代碼將在嚴(yán)格模式下執(zhí)行
- noEmitOnError - 表示當(dāng)發(fā)生錯誤的時候,編譯器不要生成 JavaScript 代碼
- noUnusedLocals 和 noUnusedParameters - 表示編譯器將檢測沒有使用的變量或參數(shù)