新建 greeter.ts
並寫入如下內容:程序員
function greeter(person) { return "Hello, " + person; } let user = "Jane User"; document.body.innerHTML = greeter(user);
安裝編譯器:typescript
npm i -g typescript
編譯:shell
tsc greeter.ts
修改 greeter.ts
文件中的代碼,爲 greeter 函數的參數 person 加上類型聲明 :string
:npm
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 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 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
也可讓咱們更容易的推測數據的流動。this
let isDone: boolean = false;
let amount: number = 6;
let nickname: string = '張三';
還可使用模板字符串(換行 + 嵌入表達式):code
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
let foo: Object = { name: 'Jack', age: 18 }
知道便可,用的不多,沒有類型校驗和語法提示
有時候,咱們會想要爲那些在編程階段還不清楚類型的變量指定一個類型。 這些值可能來自於動態的內容,好比來自用戶輸入或第三方代碼庫。 這種狀況下,咱們不但願類型檢查器對這些值進行檢查而是直接讓它們經過編譯階段的檢查。 那麼咱們可使用 any
類型來標記這些變量:
let notSure: any = 4; notSure = "maybe a string instead"; notSure = false; // okay, definitely a boolean
void
類型像是與any
類型相反,它表示沒有任何類型。 當一個函數沒有返回值時,你一般會見到其返回值類型是 void
:
function warnUser(): void { alert("This is my warning message"); }
聲明一個void
類型的變量沒有什麼大用,由於你只能爲它賦予undefined
和null
:
let unusable: void = 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