Hello World 新建 並寫入以下內容: 安裝編譯器: 編譯: 修改 文件中的代碼,為 greeter 函數的參數 person 加上類型聲明 : 重新編譯執行。 讓我們繼續修改: 重新編譯,你將看到如下錯誤: 介面(Interface) 類(Class) 變數聲明 作用域 重覆聲明 塊級作用 ...
Hello World
新建 greeter.ts
並寫入以下內容:
function greeter(person) {
return "Hello, " + person;
}
let user = "Jane User";
document.body.innerHTML = greeter(user);
安裝編譯器:
npm i -g typescript
編譯:
tsc greeter.ts
修改 greeter.ts
文件中的代碼,為 greeter 函數的參數 person 加上類型聲明 :string
:
function greeter(person: string) {
return "Hello, " + person;
}
let user = "Jane User";
document.body.innerHTML = greeter(user);
重新編譯執行。
讓我們繼續修改:
function greeter(person: string) {
return "Hello, " + person;
}
let user = [0, 1, 2];
document.body.innerHTML = greeter(user);
重新編譯,你將看到如下錯誤:
error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'.
介面(Interface)
interface Person {
firstName: string;
lastName: string;
}
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
let user = { firstName: "Jane", lastName: "User" };
document.body.innerHTML = greeter(user);
類(Class)
class Student {
fullName: string;
constructor(public firstName: string, public middleInitial: string, public lastName: string) {
this.fullName = firstName + " " + middleInitial + " " + lastName;
}
}
interface Person {
firstName: string;
lastName: string;
}
function greeter(person : Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
let user = new Student("Jane", "M.", "User");
document.body.innerHTML = greeter(user);
變數聲明
var
- 作用域
- 重覆聲明
let
- 塊級作用域
- 在同一個塊中不能重覆聲明
const
- 聲明同時必須賦值
- 一定聲明不可改變
- 對象可以修改
- 塊級作用域
let
vs const
使用最小特權原則,所有變數除了你計划去修改的都應該使用const
。 基本原則就是如果一個變數不需要對它寫入,那麼其它使用這些代碼的人也不能夠寫入它們,並且要思考為什麼會需要對這些變數重新賦值。 使用 const
也可以讓我們更容易的推測數據的流動。
基本數據類型
布爾值
let isDone: boolean = false;
數字
let amount: number = 6;
字元串
- 類型
- 模板字元串
- 支持換行
- 支持內嵌表達式
- 和 JavaScript 一樣,可以使用雙引號,也可以使用單引號,推薦單引號
let nickname: string = '張三';
還可以使用模板字元串(換行 + 嵌入表達式):
let nickname: string = `Gene`;
let age: number = 37;
let sentence: string = `Hello, my nickname is ${ nickname }.
I'll be ${ age + 1 } years old next month.`;
數組
TypeScript像JavaScript一樣可以操作數組元素。 有兩種方式可以定義數組。 第一種,可以在元素類型後面接上[]
,表示由此類型元素組成的一個數組:
let list: number[] = [1, 2, 3];
第二種方式是使用數組泛型,Array<元素類型>
:
let list: Array<number> = [1, 2, 3];
元組
元組類型允許表示一個已知元素數量和類型的數組,各元素的類型不必相同。 比如,你可以定義一對值分別為string
和number
類型的元組。
// Declare a tuple type
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
// Initialize it incorrectly
x = [10, 'hello']; // Error
Object
- 允許賦任意值
- 但是不能調用任意方法,即便它真的有
let foo: Object = {
name: 'Jack',
age: 18
}
知道即可,用的很少,沒有類型校驗和語法提示
Any
有時候,我們會想要為那些在編程階段還不清楚類型的變數指定一個類型。 這些值可能來自於動態的內容,比如來自用戶輸入或第三方代碼庫。 這種情況下,我們不希望類型檢查器對這些值進行檢查而是直接讓它們通過編譯階段的檢查。 那麼我們可以使用 any
類型來標記這些變數:
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
Void
void
類型像是與any
類型相反,它表示沒有任何類型。 當一個函數沒有返回值時,你通常會見到其返回值類型是 void
:
function warnUser(): void {
alert("This is my warning message");
}
聲明一個void
類型的變數沒有什麼大用,因為你只能為它賦予undefined
和null
:
let unusable: void = undefined;
Null 和 Undefined
和 void
相似,它們的本身的類型用處不是很大:
// Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;
預設情況下null
和undefined
是所有類型的子類型。 就是說你可以把 null
和undefined
賦值給number
類型的變數。
然而,當你指定了--strictNullChecks
標記,null
和 undefined
只能賦值給 void
和它們各自。 這能避免 很多常見的問題。許在某處你想傳入一個 string
或null
或undefined
,你可以使用聯合類型string | null | undefined
。
註意:我們推薦儘可能地使用
--strictNullChecks
,因為它使你的代碼更嚴謹,可以極大的減少出錯的幾率。
類型推斷
有時候你會遇到這樣的情況,你會比TypeScript更瞭解某個值的詳細信息。 通常這會發生在你清楚地知道一個實體具有比它現有類型更確切的類型。
通過類型斷言這種方式可以告訴編譯器,“相信我,我知道自己在乾什麼”。 類型斷言好比其它語言里的類型轉換,但是不進行特殊的數據檢查和解構。 它沒有運行時的影響,只是在編譯階段起作用。 TypeScript會假設你,程式員,已經進行了必須的檢查。
類型斷言有兩種形式。 其一是“尖括弧”語法:
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里使用JSX時,只有 as
語法斷言是被允許的。
其它
ReadonlyArray<T>
去除了數組的所有可變方法,確保數組創建後再也不能被修改
介面
TypeScript的核心原則之一是對值所具有的結構進行類型檢查。 它有時被稱做“鴨式辨型法”或“結構性子類型化”。 在TypeScript里,介面的作用就是為這些類型命名和為你的代碼或第三方代碼定義契約。
基本示例
function printLabel(labelledObj: { label: string }) {
console.log(labelledObj.label);
}
let myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);
類型檢查器會查看printLabel
的調用。 printLabel
有一個參數,並要求這個對象參數有一個名為label
類型為string
的屬性。 需要註意的是,我們傳入的對象參數實際上會包含很多屬性,但是編譯器只會檢查那些必需的屬性是否存在,並且其類型是否匹配。 然而,有些時候TypeScript卻並不會這麼寬鬆
下麵我們重寫上面的例子,這次使用介面來描述:必須包含一個label
屬性且類型為string
:
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
可選屬性
介面里的屬性不全都是必需的。 有些是只在某些條件下存在,或者根本不存在。 可選屬性在應用“option bags”模式時很常用,即給函數傳入的參數對象中只有部分屬性賦值了。
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): {color: string; area: number} {
let newSquare = {color: "white", area: 100};
if (config.color) {
newSquare.color = config.color;
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare;
}
let mySquare = createSquare({color: "black"});
只讀屬性
一些對象屬性只能在對象剛剛創建的時候修改其值。 你可以在屬性名前用 readonly
來指定只讀屬性:
interface Point {
readonly x: number;
readonly y: number;
}
你可以通過賦值一個對象字面量來構造一個Point
。 賦值後, x
和y
再也不能被改變了。
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
readonly
vs const
- 常量使用 const
- 對象屬性使用 readonly