Typescript做爲ECMA的實現,javascript的超集,目前已經普遍在項目中使用。typescript是什麼?有什麼具體功能?這些已經被你們寫得差很少了。在這裏,我再也不贅述ts的做用,而是直接用起來,從一個初學者角度告訴你們一些使用typescript的心得。下文將會完整地講解一下typescript各個方面的具體用法,力求在我總結之餘讓你們有所收穫。javascript
typescript是type+script(js)。它的本質是經過類型定義來限制js靈活多變的語法。ts提供了一些基本類型,但同時容許開發者自定義類型,在一些複雜狀況下還可使用一些高級類型。在使用以前先總結幾點能夠幫助理解的要點:html
全局安裝typescriptjava
yarn global add typescript
// 或使用 npm
npm i typescript -g
複製代碼
使用tsc進行編譯node
// 使用默認的配置編譯helloword.ts文件
tsc helloword.ts
複製代碼
使用tsconfig.json配置文件es6
// 在根目錄下創建tsconfig.json配置文件
{
// 編譯選項
"compilerOptions": {
// 編譯目標,如'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
"target": "es5",
// 編譯代碼使用的模塊 'commonjs', 'amd', 'system', 'umd' or 'es2015'
"module": "commonjs",
// 輸出文件夾,默認會對應ts文件下生成同名js文件
"outDir": "./dist",
// 類型聲明文件的目錄,工做目錄下@types文件會自動加入
"typeRoots": [],
},
// 進行編譯的文件
// 包含在files中的文件是必定會進行編譯(即便使用exclude去除)
"files": [
"hello.ts",
"word.ts"
],
// 要編譯的目錄或文件
"include": [
"./folder"
],
// 不要包含的目錄或文件
"exclude": [
"./folder/**/*.spec.ts",
"./folder/someSubFolder"
]
}
複製代碼
完整的配置選項能夠參考 typescript官網typescript
在創建好配置文件以後,直接執行tsc,編譯好的js文件便會存在於js目錄,當module爲commonjs時,能夠直接使用node進行執行測試。固然還可使用自動編譯,在tsconfig.json頂層中加入 "compileOnSave": true,告訴IDE保存後進行編譯,vscode按照typescript插件,以後執行 tsc -w
,這樣子以後就能進行自動編譯。npm
ts提供了Boolean、Number、String、Array、Tuple、Enum、Any、Void、Null、Undefined、Never、Object 共12種基本類型。json
Boolean、Number、String數組
// 大部分類型的使用很是簡單
let bool: boolean = true;
let num: number = 1213;
let str: string = "Hello World";
複製代碼
Array和Tuple(元組)bash
// 數組類型
let arr: number[] = [1213,2324]
// 或者
const arr2: Array<string> = ['1213', '234234']
// 元組爲有限個有序的數組,元組須要對數組的每一個元素聲明類型
let tup: [string, number] = ["121", 2321];
tup[0] = "wadsas";
tup[0] = 1212 // 報錯
複製代碼
Enum類型
枚舉類型是一種很特殊的類型,其它的類型聲明在編譯成js代碼以後便不會存在,但枚舉類型是會編輯成js代碼的。
enum Tristate {
False,
True,
Unknown
}
// 編譯成js以後
var Tristate;
(function(Tristate) {
Tristate[(Tristate['False'] = 0)] = 'False';
Tristate[(Tristate['True'] = 1)] = 'True';
Tristate[(Tristate['Unknown'] = 2)] = 'Unknown';
})(Tristate || (Tristate = {}));
// 也就是如下對象
{0: "False", 1: "True", 2: "Unknown", False: 0, True: 1, Unknown: 2}
let tri: Tristate = Tristate.False
複製代碼
枚舉選項的值默認是從0開始,上面的Tristate中False爲0, True爲1,Unknown爲2,咱們能夠改變枚舉的值:
enum HighColor {
Green,
Black = 5,
Blue
}
// Green爲0,Black爲5,Blue爲6
// 字符串枚舉
enum Type {
ON_LINE = "ON_LINE",
DOWN = "DOWN",
OTHER = "OTHER"
}
複製代碼
還可使用 enum + namespace 的聲明的方式向枚舉類型添加靜態方法
enum PersonType {
young,
middle,
old
}
namespace PersonType {
export function isOld(person: PersonType) {
return person === PersonType.old;
}
}
const Marry: PersonType = PersonType.old;
console.log(PersonType.isOld(Marry));
複製代碼
Any和Object
Any是任意類型,當一個變量被聲明爲了any類型,它能夠是任何值,就如js同樣能夠隨意改變其值而不會有提示,當從js項目遷移到ts,any能夠提供極大的便利,但一個項目內應該儘可能少地使用any類型,由於這意味着你放棄類型檢查。
let a: any = 1231;
a = "12313";
a = true
複製代碼
Object是對象類型,它僅表示變量是對象類型,不會對對象的屬性作出限制,一個比較適合的場景是Object.create(o: object)
。
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
create(42); // Error
let obj: object = {a: 12}
obj = {b: 12, c: 88}
obj.d = 1212 // 報錯
複製代碼
Void、Never、Null和Undefined
Void通常用以表示函數或方法沒有返回值,Never表明永遠不會發生的類型。
function log(name: string):void {
console.log(name)
}
// 拋出了錯誤,程序永遠沒有返回值
function error(message: string): never {
throw new Error(message);
}
// 函數內有一個死循環,永遠不會執行到循環外的代碼
function infiniteLoop(): never {
while (true) {
}
}
複製代碼
Null和Undefined類型爲其它全部類型的子類型,這意味着該類型能夠賦值爲其它任何類型,但這必須在strictNullChecks編譯選項爲false的狀況下。
let n: null = null
let u: undefined = undefined;
let str: string = '1212'
str = n
複製代碼
內聯方式
let person: {name: string, age: number} = {name: '小龍女', age: 12}
複製代碼
內聯方式聲明自定義類型較爲直接,但其聲明的類型沒法複用。
聲明函數
函數能夠直接使用function聲明類型,如函數變量則能夠直接經過內聯方式聲明。
// 使用function進行聲明
function log(str: string): void {
console.log(str);
}
// 對函數變量進行聲明
interface Log {
(str: string): boolean;
}
type Log2 = {
(str: string): boolean;
}
const myLog: Log = str => {
console.log(str);
return true;
};
// 直接使用箭頭進行函數聲明
const toDo: (str: string) => void = str => {
console.log(str);
};
複製代碼
經過class聲明類型
es6新增的class能夠直接聲明類型,並且對於靜態屬性、靜態函數的聲明很是方便:
class Cat {
name: string;
static Type: string;
}
// Cat.Type 會是string類型
const cat: Cat = new Cat();
複製代碼
interface和type
interface和type大同小異,均可用於自定義類型,建議直接使用interface聲明類型,在interface沒法實現時使用type。
interface Point {
x: number;
y: number;
// 加?號表示可選
x2?: number;
// 聲明方法
computed?():void
}
// 同名接口合併,下面接口能夠與上面的Point接口合併
interface Point {
x2: number;
}
// 接口繼承
interface Point_3D extends Point {
z: number;
}
// 接口能夠被class實現
class ChartPoint implements Point {
x: number;
y: number;
constructor(x, y) {
this.x = x;
this.y = y;
}
}
// 使用type聲明一個類型
type Person = {
name: string;
age: number;
sex: string;
showInfo(isLog: boolean):string;
}
// 爲Point接口取個別名
type Point2 = Point
複製代碼
有一些狀況下只能使用type進行自定義類型聲明:
interface Person {
name: string;
age: number;
sex: string;
id: string;
}
// SubPerson類型的全部屬性都存在於Person類型中
type SubPerson = {
[key in keyof Person]: Person[key];
};
function createSubPerson( person: Person, keys: Array<keyof Person> ): SubPerson {
return keys.reduce(
(obj, key) => ({ ...obj, [key]: person[key] }),
{} as SubPerson
);
}
複製代碼
我認爲學習ts比較重要的是區分類型與變量,類型和變量是能夠重名的,有些操做是針對類型,如keyof;有些則是針對變量, 如instanceof;有些則是二者皆可, 如typeof。事實上分清類型與變量一點也不容易。在ts中,值也是一種類型——字面量類型(literal type)
// 全部的值均可以做爲類型
// 字面量類型
let foo: "Hello"; // foo的值只能爲Hello
foo = "Hello";
let num: 12;
num = 12;
let bool: true = true;
let obj2: { a: 121 } = { a: 121 };
複製代碼
變量只能爲一個固定的值,這樣看來字面量類型彷佛沒有什麼價值?結合聯合類型會讓其大有所爲:
type Strs = "a" | "b" | "c" | "d";
type Nums = 1 | 2 | 3 | 4 | 5;
type Bools = true | false;
let str:Strs = 'a' // str只能爲a、b、c、d中的一個
// 對象和聯合類型實現枚舉類型的功能
// 枚舉類型是一種奇特的類型,既能夠充當類型,又能夠當成對象進而訪問它的屬性
// strEnum將數組轉爲對象
function strEnum(o: Array<T>): { [K in T]: K } {
return o.reduce((res, key) => {
res[key] = key;
return res;
}, Object.create({}));
}
const OTHER = strEnum(["North", "South", "East", "West"]); //此處OTHER是對象
type OTHER = keyof typeof OTHER; // 此處OTHER爲類型
// 如今OTHER具有了枚舉類型的所有特性
let other2: OTHER;
other2 = OTHER.East;
複製代碼