
基於2018年Stack Overflow Developer的調研,TypeScript
做爲編程語言比JavaScript更受「喜好」。TypeScript在js開發者中這麼受喜好的緣由是:在你運行代碼前,添加到javascript中的類型有助你發現錯誤(代碼)。TypeScript編譯器提供的錯誤能夠很好的引導你如何修復代碼錯誤。往javascript中添加類型同時有助代碼編輯器提供一些高級的功能,例如代碼完成,項目範圍的重構和自動模塊的導入。javascript

若是你認爲TypeScript是一門全新的編程語言,那麼學習它可能使人生畏。然而,TypeScript只是JavaScript的一個附加層(超集),在使用TypeScript前,你無需瞭解它的每一個語法。TypeScript容許你經過更改文件的後綴名.js
爲.ts
來輕鬆的轉換javascript文件,而且全部的代碼將做爲TypeScript來正確編譯。若是你想在TypeScript文件中強制執行更廣的類型覆蓋百分比,你能夠將TypeScript配置得更具侷限性,一旦你熟悉該語言了,你就能夠完成此操做。html
本文旨在帶你快速瞭解一個標準的TypeScript項目中會遇到的95%的場景。剩餘的5%,嗯,你能夠google,還有,我會在本文底部放些有用的TypeScript資源連接。java
配置TypeScript
固然,要開始編寫能正確編譯的TypeScript(文件),正確配置開發環境是必要的。git
一、安裝TypeScript編譯器github
首先,爲了可以將TypeScript文件轉換成JavaScript文件,咱們須要安裝TypeScript編譯器。安裝TypeScript可全局安裝(文件系統中安裝,能夠在任何位置使用)或者本地安裝(僅在項目級別可以使用)。【我的偏向後者】算法
# NPM Installation Method
npm install --global typescript # Global installation
npm install --save-dev typescript # Local installation
# Yarn Installation Method
yarn global add typescript # Global installation
yarn add --dev typescript # Local installation
複製代碼
二、確保你的編輯器設置爲支持TypeScripttypescript
你須要確保正確配置了你的編輯器以使用TypeScript。好比,爲了在編輯器中能更好得使用TypeScript,你須要安裝一個插件(若是你使用atom,你能夠安裝 atom-typescript)。若是你使用的是VS Code編輯器
,那麼你不須要安裝額外的插件了,由於它內置了TypeScript的支持。😎npm
三、新建tsconfig.json文件編程
tsconfig.json文件是用來配置TypeScript項目設置。它應該放在項目的根目錄中。該文件容許你使用不一樣的選項配置TypeScript編譯器。json
若是你僅僅是想TypeScript生效的話,你只須要tsconfig.json文件中包含一個空JSON對象,可是,若是你須要TypeScript編譯器的有不一樣的行爲(好比在特定的輸出目錄中輸出編譯後的JavaScript文件),你能夠閱讀更多有關能夠配置哪些設置的(內容)。
備註:你也能夠經過運行
tsc --init
去生成一個tsconfig.json文件,其中爲你設置了些默認選項,還有一些被註釋掉的其餘選項。
四、將TypeScript轉化爲JavaScript
爲了將你的TypeScript代碼轉化成JavaScript代碼,須要在控制檯上跑tsc命令。運行tsc命令將告訴TypeScript編譯器去搜索tsconfig.json
文件,該文件將肯定項目的根目錄以及編譯TypeScript並將.ts
文件轉換爲.js
文件時用的選項。
爲了快速驗證設置生效,你能夠建立一個測試的TypeScript文件,而後在命令行中運行tsc
,以後查看下TypeScript文件旁邊是否生成了JavaScript文件。
舉個例子,TypeScript文件以下...
const greeting = (person: string) => {
console.log('Good day ' + person);
};
greeting('Daniel');
複製代碼
應該被轉換爲下面這個JavaScript文件了...
var greeting = function(person) {
console.log('Good day ' + person);
};
greeting('Daniel');
複製代碼
若是你想TypeScript編譯器(動態)監視TypeScript文件內容的變動,並自動將.ts
文件轉換成.js
文件,你能夠在你項目的倉庫(命令行)中運行tsc -p
。
在VS Code(編輯器)中,你可使用⌘⇧B調出一個菜單,該菜單(包含)能夠在正常模式和監視模式下運行轉換程序(分別對應tsc:build
和tsc:watch
)。

瞭解靜態和動態類型
JavaScript附帶7種動態類型:
- Undefined
- Null
- Boolean
- Number
- String
- Symbol
- Object
上面的類型被稱爲動態類型,由於它們在運行時使用。
TypeScript爲JavaScript語言帶來了靜態類型,而且這些類型在編譯時(無需運行代碼)被肯定。靜態類型能夠預測動態類型的值,這能夠幫助在無需運行代碼的狀況下警告你可能出現的錯誤。
基本靜態類型
好吧,咱們來深刻研究下TypeScript的語法。如下是TypeScript中最多見的類型。
備註:我遺漏了never和object類型,由於根據個人經驗,它們並不被常用。
boolean
你已經很瞭解true
和false
值了。
let isAwesome: boolean = true;
複製代碼
string
文本數據用單引號('')或雙引號("")或後標記(``)【也稱模版字符】包圍。
let name: string = 'Chris';
let breed: string = 'Border Collie';
複製代碼
若是你使用後標誌,該字符串被稱爲模版文字,能夠在裏面插入表達式。
let punchline: string = 'Because it was free-range.';
let joke: string = ` Q: Why did the chicken cross the road? A: ${punchline} `;
複製代碼
number
任何浮點數都給定爲數字類型。做爲TypeScript的一部分,支持的四種類型的數字文字是二進制,十進制,八進制和十六進制。
let decimalNumber: number = 42;
let binaryNumber: number = 0b101010; // => 42
let octalNumber: number = 0o52; // => 42
let hexadecimalNumber: number = 0x2a; // => 42
複製代碼
備註:並非只有你一我的對二進制,八進制和十六進制數字感到困惑。
array
TypeScript中有兩種書寫數組類型的方式。第一種是[]後綴在須要查找的數組元素類型。
let myPetFamily: string[] = ['rocket', 'fluffly', 'harry'];
複製代碼
另外一種可替代的方式是,Array後跟要查找的數組元素類型的Array
類型(使用尖括號包含)。
let myPetFamily: Array<string> = ['rocket', 'fluffly', 'harry'];
複製代碼
tuple
元組是一個包含固定數量的元素和相關類型的數組。
let myFavoriteTuple: [string, number, boolean];
myFavoriteTuple = ['chair', 20, true]; // ✅
myFavoriteTuple = [5, 20, true]; // ❌ - The first element should be a string, not a number
複製代碼
enum
枚舉將名稱和常量值關聯,能夠是數字或者字符串。當你想一組具備關聯性的描述名稱的不一樣值,枚舉就頗有用處了。
默認,爲枚舉分配從0開始的值,接下來的值爲(上一個枚舉值)加1。
enum Sizes {
Small,
Medium,
Large,
}
Sizes.Small; // => 0
Sizes.Medium; // => 1
Sizes.Large; // => 2
複製代碼
第一個值也能夠設置爲非0的值。
enum Sizes {
Small = 1,
Medium,
Large,
}
Sizes.Small; // => 1
Sizes.Medium; // => 2
Sizes.Large; // => 3
複製代碼
枚舉默認是被分配數字,然而,字符串也能夠被分配到一個枚舉中的。
enum ThemeColors {
Primary = 'primary',
Secondary = 'secondary',
Dark = 'dark',
DarkSecondary = 'darkSecondary',
}
複製代碼
any
若是變量的類型未知,而且咱們並不但願類型檢查器在編譯時抱怨,則可使用any
類型。
let whoKnows: any = 4; // assigned a number
whoKnows = 'a beautiful string'; // can be reassigned to a string
whoKnows = false; // can be reassigned to a boolean
複製代碼
在開始使用TypeScript的時,可能會頻繁使用any
類型。然而,最好嘗試減小any
的使用,由於當編譯器不知道與變量相關的類型時,TypeScript的有用性會下降。
void
當沒有與事物相關類型的時候,void
類型應該被使用。在指定不返回任何內容的函數返回值時,最經常使用它。
const darkestPlaceOnEarth = (): void => {
console.log('Marianas Trench');
};
複製代碼
null和undefined
null和undefined都對應你在javascript中看到的null和undefined值的類型。這些類型在單獨使用的時候不是頗有用。
let anUndefinedVariable: undefined = undefined;
let aNullVariable: null = null;
複製代碼
默認狀況下,null和undefined類型是其餘類型的子類型,這意味着能夠爲string類型的變量賦值爲null或者undefined。這一般是不合理的行爲,因此一般建議將tsconfig.json
文件中的strictNullChecks編譯器選項設置爲true。將strictNullChecks設置爲true,會使null和undefined須要顯示設置爲變量的類型。
類型推斷
幸運的是,你不須要在代碼中所有位置指定類型,由於TypeScript具備類型推斷。類型推斷是TypeScript編譯器用來自行決定類型的(內容)。
基本類型推斷
TypeScript能夠在變量初始化期間,設置默認參數以及肯定函數返回值時推斷類型。
// Variable initialization
let x = 10; // x is given the number type
複製代碼
在上面的例子中,x
被分配了數字,TypeScript會以number
類型將x
變量關聯起來。
// Default function parameters
const tweetLength = (message = 'A default tweet') => {
return message.length;
};
複製代碼
在上面的例子中,message參數被賦予了一個類型爲string的默認值,所以TypeScript編譯器會推斷出message的類型是string,所以在訪問length屬性的時候並不會拋出編譯錯誤。
function add(a: number, b: number) {
return a + b;
}
const result = add(2, 4);
result.toFixed(2); // ✅
result.length; // ❌ - length is not a property of number types
複製代碼
在上面這個例子中,由於TypeScript告訴add
函數,它的參數都是number
類型,那麼能夠推斷得出返回的類型也應該是number
。
最佳通用類型推斷
從多種可能的類型中推斷類型時,TypeScript使用最佳通用類型算法來選擇適用於全部其餘候選類型的類型。
let list = [10, 22, 4, null, 5];
list.push(6); // ✅
list.push(null); // ✅
list.push('nope'); // ❌ - type 'string' is neither of type 'number' or 'null'
複製代碼
在上面的例子中,數組(list)是由number
或null
類型組成的,所以TypeScript只但願number
或null
類型的值加入數組。
類型註釋
當類型推斷系統不夠用的時,你須要在變量和對象上聲明類型。
基本類型
在(上面)基本靜態類型章節的介紹中,全部的類型都使用:
後跟類型名來聲明。
let aBoolean: boolean = true;
let aNumber: number = 10;
let aString: string = 'woohoo';
複製代碼
Arrays
在(上面)講到的array
類型的章節中,arrays能夠經過兩種方式的其中一種進行註釋。
// First method is using the square bracket notation
let messageArray: string[] = ['hello', 'my name is fred', 'bye'];
// Second method uses the Array keyword notation
let messageArray: Array<string> = ['hello', 'my name is fred', 'bye'];
複製代碼
接口
將多種類型的註釋組合到一塊兒的一種方法是使用接口。
interface Animal {
kind: string;
weight: number;
}
let dog: Animal;
dog = {
kind: 'mammal',
weight: 10,
}; // ✅
dog = {
kind: true,
weight: 10,
}; // ❌ - kind should be a string
複製代碼
類型別名
TypeScript使用Type Alias指定多個類型註釋,這事(讓人)有些疑惑。【下面講到】
type Animal = {
kind: string;
weight: number;
};
let dog: Animal;
dog = {
kind: 'mammal',
weight: 10,
}; // ✅
dog = {
kind: true,
weight: 10,
}; // ❌ - kind should be a string
複製代碼
在使用接口或類型別名這方面,最佳的作法彷佛是,在代碼庫保持一致狀況下,一般選擇接口類型或類型別名。可是,若是編寫其餘人可使用的第三方的公共API,就要使用接口類型了。
若是你想了解更多關於type alias
和interface
的比較的話,我推薦你看Martin Hochel的這篇文章。
內聯註釋
相比建立一個可複用的接口,有時內聯註釋類型可能更合適。
let dog: {
kind: string;
weight: number;
};
dog = {
kind: 'mammal',
weight: 10,
}; // ✅
dog = {
kind: true,
weight: 10,
}; // ❌ - kind should be a string
複製代碼
泛型
某些狀況下,變量的特定類型可有可無,可是應強制執行不一樣變量和類型之間的關係。針對這些狀況,應該使用泛型類型。
const fillArray = <T>(len: number, elem: T) => {
return new Array<T>(len).fill(elem);
};
const newArray = fillArray<string>(3, 'hi'); // => ['hi', 'hi', 'hi']
newArray.push('bye'); // ✅
newArray.push(true); // ❌ - only strings can be added to the array
複製代碼
上面的示例中有一個泛型類型T
,它對應於傳遞給fillArray
函數的第二個參數類型。傳遞給fillArray
函數的第二個參數是一個字符串,所以建立的數組將其全部元素設置爲具備字符串類型。
應該注意的是,按照慣例,單個(大寫)字母用於泛型類型(好比:T
或K
)。但是,並不限制你使用更具備描述性的名稱來表示你的泛型類型。下面示例就是爲所提供的泛型類型使用了更具備描述性的名稱:
const fillArray = <ArrayElementType>(len: number, elem: ArrayElementType) => {
return new Array<ArrayElementType>(len).fill(elem);
};
const newArray = fillArray<string>(3, 'hi'); // => ['hi', 'hi', 'hi']
newArray.push('bye'); // ✅
newArray.push(true); // ❌ - only strings can be added to the array
複製代碼
聯合類型
在類型能夠是多種類型之一的狀況下,使用|
分隔符隔開不一樣類型的選項來使用聯合類型。
// The `name` parameter can be either a string or null
const sayHappyBirthdayOnFacebook = (name: string | null) => {
if (name === null) {
console.log('Happy birthday!');
} else {
console.log(`Happy birthday ${name}!`);
}
};
sayHappyBirthdayOnFacebook(null); // => "Happy birthday!"
sayHappyBirthdayOnFacebook('Jeremy'); // => "Happy birthday Jeremy!"
複製代碼
交集類型
交集類型使用&
符號將多個類型組合在一塊兒。這和(上面的)聯合類型不一樣,由於聯合類型是表示結果的類型是列出的類型之一,而交集類型則表示結果的類型是全部列出類型的集合。
type Student = {
id: string;
age: number;
};
type Employee = {
companyId: string;
};
let person: Student & Employee;
person.age = 21; // ✅
person.companyId = 'SP302334'; // ✅
person.id = '10033402'; // ✅
person.name = 'Henry'; // ❌ - name does not exist in Student & Employee
複製代碼
元組類型
元組類型使用一個:
符號,其後跟一個使用中括號包含且逗號分隔的類型列表表示。
let list: [string, string, number];
list = ['apple', 'banana', 8.75]; // ✅
list = ['apple', true, 8.75]; // ❌ - the second argument should be of type string
list = ['apple', 'banana', 10.33, 3]; // ❌ - the tuple specifies a length of 3, not 4
複製代碼
可選類型
可能存在函數參數或者對象屬性是可選的狀況。在這些狀況下,使用?
來表示這些可選值。
// Optional function parameter
function callMom(message?: string) {
if (!message) {
console.log('Hi mom. Love you. Bye.');
} else {
console.log(message);
}
}
// Interface describing an object containing an optional property
interface Person {
name: string;
age: number;
favoriteColor?: string; // This property is optional
}
複製代碼
有幫助的資源
本文中未涉及到的TypeScript內容,我推薦如下的資源。
TypeScript Handbook (Official TypeScript docs)
TypeScript Deep Dive (Online TypeScript Guide)
Understanding TypeScript's Type Annotation (Great introductory TypeScript article)
本文同步分享在 博客「Jimmy」(JueJin)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。