typescript基本使用筆記
安裝typescript
npm install -g typescript 全局安裝ts
tsc *.ts 編譯ts文件編譯成js文件,如果ts有語法錯誤,則會編譯報錯,但是仍然會創(chuàng)建編譯好的js文件并且編譯執(zhí)行
基礎類型
定義變量或者參數(shù)的時候通過 :號指定類型
-
boolean 布爾型
-
number 數(shù)字型:包括各種進制的數(shù)值型,浮點型
-
string 字符串類型:可以使用模板字符串
-
number[]/Array<number> 數(shù)組類型:寫法有兩種一種是number后面加
[],一種是通過數(shù)組Array 泛型 -
tuple :一個已知元素長度和類型的數(shù)組,且類型不能重復,
屬于聯(lián)合類型 -
enum 枚舉類型:使用枚舉類型可以為一組數(shù)值賦予友好的名字,一種類似數(shù)組的引用類型形式,可以通過下標訪問和賦值,也可以指定下標
-
any :任意類型,不會進行類型檢查,任意類型都可以通過,可以組和,比如
any[]表示任意元素類型的數(shù)組 -
void : 空類型,通常用來表示無返回值,
只能夠賦值為:undefined和null -
null和undefined :默認是所有類型的子集,意思是所有其他類型都可以賦值成null和undefined類型
-
never :不應該運行到此處的類型,
-
object :非原始類型,除了
string,number,boolean,null,undefined,symbol這幾個js的基本類型 類型斷言(類型轉(zhuǎn)換):語法為 let someValue :any = 'Word' 可以強行將右邊轉(zhuǎn)為左邊 ;另一個方法是'as'語法,let strLength: number = (someValue as string).length;
變量聲明
-
let和var的區(qū)別(略)
-
解構(gòu) --快速的變量賦值
//---------------數(shù)組解構(gòu)---------------------
// 數(shù)組解構(gòu)
let input = [1, 2];
let [first, second] = input;
console.log(first); // outputs 1
console.log(second); // outputs 2
//剩余變量的數(shù)組解構(gòu)
let [first, ...rest] = [1, 2, 3, 4];
console.log(first); // outputs 1
console.log(rest); // outputs [ 2, 3, 4 ]
//對應下標的數(shù)組解構(gòu)
let [, second, , fourth] = [1, 2, 3, 4];
//------------------對象解構(gòu)---------------
let o = {
a: "foo",
b: 12,
c: "bar"
};
let { a, b } = o;
//快速的將o對應的鍵值賦給a,b
let { a, ...passthrough } = o;
let total = passthrough.b + passthrough.c.length;
//剩余變量的對象解構(gòu)
let { a: newName1, b: newName2 } = o;
//變量重命名,此處相當于{a,b}=0 newName1 = a,newName2 = b;
//此處的:相當于賦值符號
//為什么這里的:不是類型聲明符號?
//因為:解構(gòu)時如果需要類型聲明需要完整的寫類型模式
//例如:let {a, b}: {a: string, b: number} = o;
function keepWholeObject(wholeObject: { a: string, b?: number }) {
let { a, b = 1001 } = wholeObject;
//解構(gòu)時的默認值,如果不存在b這個鍵值時,b=1001
}
//--------------函數(shù)聲明-----------------------
type C = { a: string, b?: number }
function f({ a, b }: C): void {
// ...
}
//將解構(gòu)元素當作參數(shù)傳遞
function f({ a="", b=0 } = {}): void {
// ...
}
f();
//解構(gòu)傳參帶默認值
function f({ a, b = 0 } = { a: "" }): void {
// ...
}
f({ a: "yes" }); // ok, default b = 0
f(); // ok, default to {a: ""}, which then defaults b = 0
f({}); // error, 'a' is required if you supply an argument
//解構(gòu)+默認賦值,默認傳入{a:""}如果啥也不傳,默認參數(shù)為{a:''},那么a='',b=0
-
展開 --與解構(gòu)相反將數(shù)組展開或者將對象展開
//所有的展開都是淺拷貝?。?
//將數(shù)組展開并且插入新數(shù)組
let first = [1, 2];
let second = [3, 4];
let bothPlus = [0, ...first, ...second, 5];
//將對象展開
let defaults = { food: "spicy", price: "$$", ambiance: "noisy" };
let search = { ...defaults, food: "rich" };
//對象展開會丟失對象方法
class C {
p = 12;
m() {
}
}
let c = new C();
let clone = { ...c };
clone.p; // ok
clone.m(); // error!
接口
接口的作用就是為這些類型命名和代碼進行綁定,接口一般用來做函數(shù)參數(shù)的預定義
-
關鍵字 interface
interface LabelledValue {
//定義一個接口
label: string;
//接口中定義了label這個字段必須是字符串類型
}
function printLabel(labelledObj: LabelledValue) {
//參數(shù)labelledObj 套用這個接口,所以參數(shù)必須有l(wèi)abel字段并且為string類型
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
-
可選參數(shù)接口
interface SquareConfig {
color?: string; //只是在類型聲明符前面增加了一個問號
width?: number;
}
-
只讀屬性
只能在對象剛創(chuàng)建的時候?qū)ζ渲颠M行修改,可以在屬性名前面增加
readonly來指定只讀屬性 -
額外的屬性檢查
interface SquareConfig {
color?: string;
width?: number;
[propName: string]: any;
//使用propName內(nèi)置屬性獲取接口的其他參數(shù)傳值,并且對其進行單獨的檢查
}
-
函數(shù)類型 接口也能用來描述函數(shù)類型
interface SearchFunc {
(source: string, subString: string): boolean;
//定義了一個函數(shù)接口,參數(shù)為source和substring類型為string類型,返回值為boolean類型
}
//以下兩種調(diào)用方式都符合邏輯
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
}
-
可索引的類型 可以自定義接口用來限定可索引類型的類型解構(gòu)
//基礎的引用類型接口
interface StringArray {
[index: number]: string;
//定義一個索引類型的接口:
//":"左邊表示索引的類型定義,右邊表示值的類型定義
//所以上面的意思是定義了一個索引類型的接口,index必須是number類型,值必須是string類型
//嵌套設計
interface NumberDictionary {
[index: string]: number;
//定義了該索引類型的index是string類型,值是number類型
length: number; // 可以,length是number類型
//legth字段定義成number類型,length也屬于該索引類型的index,其值也要是number類型
name: string // 錯誤,`name`的類型與索引類型返回值的類型不匹配
//同理,name也是index,該值也必須是number類型
}
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
//只讀索引的接口設計
interface ReadonlyStringArray {
readonly [index: number]: string;
//設定index的類型為只讀類型,值為string類型
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
//由于設置了index的只讀類型,所以無法進行修改
myArray[2] = "Mallory"; // error!
-
類類型 與C#或Java里接口的基本作用一樣,TypeScript也能夠用它來明確的強制一個類去符合某種契約。
interface ClockInterface {
currentTime: Date;
//定義了一個類型型的接口,其currentTime屬性必須是一個Date類型
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number) { }
}
//類類型使用方法如下
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
//implements為關鍵字,表示該類使用ClockInterface這個接口
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
//類靜態(tài)部分和實例部分的區(qū)別
interface ClockConstructor {
new (hour: number, minute: number);
}
class Clock implements ClockConstructor {
currentTime: Date;
constructor(h: number, m: number) { }
//constructor構(gòu)造函數(shù)里面的參數(shù)為類的靜態(tài)屬性所以不會適用上面那個接口的檢測方法
}
//--------------------復雜的類類型例子--------------------------------------
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick();
}
function createClock(ctor: ClockConstructor, hour: number, minute: number):
//聲明一個函數(shù)
//函數(shù)的參數(shù)接口定義是 ctor的接口是ClockConstructor,hour是number類型,minute是number
//ClockConstructor又是一個函數(shù)接口,表示構(gòu)造函數(shù)參數(shù)hour和minute的類型都是number,且必須具有屬性ClockInterface接口,也就是必須有這個tick屬性或者方法
//通過這樣嵌套,達到對構(gòu)造函數(shù)靜態(tài)參數(shù)的接口定義
ClockInterface {
//函數(shù)的返回值是ClockInterface這個接口定義的,必須有tick這個屬性或者方法
return new ctor(hour, minute);
}
class DigitalClock implements ClockInterface {
constructor(h: number, m: number) { }
tick() {
console.log("beep beep");
}
}
class AnalogClock implements ClockInterface {
constructor(h: number, m: number) { }
tick() {
console.log("tick tock");
}
}
let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);
-
接口的繼承 和類一樣,接口也可以相互繼承。 這讓我們能夠從一個接口里復制成員到另一個接口里,可以更靈活地將接口分割到可重用的模塊里。
interface Shape {
color: string;
}
interface Square extends Shape {
//關鍵字extend Square繼承自Shape
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
// 一個接口可以繼承多個接口,創(chuàng)建出多個接口的合成接口。
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
-
混合類型 一個接口可以同時擁有多種類型接口的特性,實現(xiàn)該接口的多類型
interface Counter {
//定義一個接口Counter
(start: number): string;
//擁有函數(shù)接口類型的特性,定義了參數(shù)和返回值的類型
interval: number;
//同時定義了對象類型的特性,可以擁有屬性
reset(): void;
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
-
接口繼承類 當一個接口繼承一個類,會繼承其類的成員,但是不包括其實現(xiàn),
class Control {
private state: any;
}
interface SelectableControl extends Control {
//該接口繼承自類Control,所以也會繼承其屬性,包括私有屬性
//所以再次使用該接口的時候,會繼承該私有屬性的定義
select(): void;
}
class Button extends Control implements SelectableControl {
select() { }
}
class TextBox extends Control {
select() { }
}
// 錯誤:“Image”類型缺少“state”屬性。
class Image implements SelectableControl {
select() { }
}
class Location {
}
//在上面的例子里,SelectableControl包含了Control的所有成員,包括私有成員state。 因為 state是私有成員,所以只能夠是Control的子類們才能實現(xiàn)SelectableControl接口。 因為只有 Control的子類才能夠擁有一個聲明于Control的私有成員state,這對私有成員的兼容性是必需的。
//在Control類內(nèi)部,是允許通過SelectableControl的實例來訪問私有成員state的。 實際上, SelectableControl接口和擁有select方法的Control類是一樣的。 Button和TextBox類是SelectableControl的子類(因為它們都繼承自Control并有select方法),但Image和Location類并不是這樣的。