TS文檔的搬運(yùn)工

你會玩Javascript多級繼承嗎怠益?
你能說明白js的作用域嗎贮乳?
曾經(jīng)有個(gè)面試題忧换,用console.log寫一個(gè)方法,要求輸入1向拆,輸出的是0亚茬,結(jié)果

const console = Math
console.log(1) // 0

實(shí)際上,JavaScript里面充斥著大量的彩蛋浓恳,消耗大家非常多的時(shí)間刹缝。
JavaScript這門語言一直以來為什么會表現(xiàn)得這么詭異呢葡兑?一定要看阮老師的這篇文章Javascript誕生記
我們再看看TS的代碼長什么樣子
Validation.ts

export interface StringValidator {
    isAcceptable(s: string): boolean;
}

LettersOnlyValidator.ts

import { StringValidator } from "./Validation";

const lettersRegexp = /^[A-Za-z]+$/;

export class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
        return lettersRegexp.test(s);
    }
}

仔細(xì)看你會發(fā)現(xiàn),TS跟我們現(xiàn)在用的es6很像赞草,我們學(xué)習(xí)TS并沒有什么學(xué)習(xí)成本。
而TS無論可讀性吆鹤、可維護(hù)性厨疙、上手的容易程度、寫代碼的速度疑务,都非常明顯地優(yōu)于JS沾凄。


TS入門

基礎(chǔ)類型

布爾值、數(shù)字知允、字符串撒蟀、數(shù)組、元組温鸽、枚舉保屯、anyvoid涤垫、Null 和 Undefined姑尺、Never類型斷言

let isDone: boolean = false; // 布爾值

// 數(shù)字類型蝠猬,支持十進(jìn)制和十六進(jìn)制切蟋,二進(jìn)制和八進(jìn)制字面量
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;

let sentence: string = `Hello, my name is ${ name }.`; // 字符串類型

// 數(shù)組類型 類型+[]
let list: number[] = [1, 2, 3]; // 可以在元素類型后面接上 [],表示由此類型元素組成的一個(gè)數(shù)組
let list: Array<number> = [1, 2, 3];// 使用數(shù)組泛型榆芦,Array<元素類型>
// (number | string)[]這是聯(lián)合類型和數(shù)組的結(jié)合
// any[] 任意類型和數(shù)組的結(jié)合

// 元組類型 元組類型允許表示一個(gè)已知元素?cái)?shù)量和類型的數(shù)組柄粹,各元素的類型不必相同
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
x = [10, 'hello']; // Error

// 枚舉類型
enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;

// 任意類型
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

// void 表示沒有任何類型
let unusable: void = undefined;// 聲明一個(gè)void類型的變量沒有什么大用,因?yàn)槟阒荒転樗x予undefined和null

// null和undefined 類型 Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;
// never 類型 返回never的函數(shù)必須存在無法達(dá)到的終點(diǎn)
function error(message: string): never {
    throw new Error(message);
}

類型斷言
語法
<類型>值
值 as 類型(JSX)

let strLength: number = (<string>someValue).length; //(尖括號)
let strLength: number = (someValue as string).length; // as語法

當(dāng) TypeScript 不確定一個(gè)聯(lián)合類型的變量到底是哪個(gè)類型的時(shí)候匆绣,我們只能訪問此聯(lián)合類型的所有類型里共有的屬性或方法

// error
function getLength(something: string | number): number {
    return something.length;
}
// error
function getLength(something: string | number): number {
    if (something.length) {
        return something.length;
    } else {
        return something.toString().length;
    }
}
// 使用類型斷言驻右,將something斷言成 string
function getLength(something: string | number): number {
    if ((<string>something).length) {
        return (<string>something).length;
    } else {
        return something.toString().length;
    }
}
// 類型斷言不是類型轉(zhuǎn)換,斷言成一個(gè)聯(lián)合類型中不存在的類型是不允許的
// error
function toBoolean(something: string | number): boolean {
    return <boolean>something;
}

類型推論
TypeScript 會在沒有明確的指定類型的時(shí)候推測出一個(gè)類型犬绒,這就是類型推論旺入。

// 類型推論
let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;// error TS2322: Type 'number' is not assignable to type 'string'.
// 等價(jià)于
let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;

// 如果定義的時(shí)候沒有賦值,不管之后有沒有賦值凯力,都會被推斷成 any 類型而完全不被類型檢查
let myFavoriteNumber;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

聯(lián)合類型
聯(lián)合類型使用 | 分隔每個(gè)類型

let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
myFavoriteNumber = true; // Type 'boolean' is not assignable to type 'string | number'.

變量聲明

let 變量聲明
const 常量聲明
ts跟es6一樣推薦使用 let 和 const茵瘾,因?yàn)樗麄兌际菈K級作用域;不存在變量提升咐鹤;
var 作為一個(gè)全局變量拗秘,易造成環(huán)境的變量污染;

”變量提升“祈惶,即變量可以在聲明之前使用雕旨,值為undefined扮匠。這種現(xiàn)象多多少少是有些奇怪的,按照一般的邏輯凡涩,變量應(yīng)該在聲明語句之后才可以使用棒搜。為了糾正這種現(xiàn)象,let命令改變了語法行為活箕,它所聲明的變量一定要在聲明后使用力麸,否則報(bào)錯(cuò)。

// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;

// let 的情況
console.log(bar); // 報(bào)錯(cuò)ReferenceError
let bar = 2;

”暫時(shí)性死區(qū)“(temporal dead zone育韩,簡稱 TDZ)克蚂,即只要塊級作用域內(nèi)存在let命令,它所聲明的變量就“綁定”(binding)這個(gè)區(qū)域筋讨,不再受外部的影響埃叭。

var tmp = 123;

if (true) {
  // TDZ開始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ結(jié)束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

結(jié)構(gòu)賦值

// 數(shù)組結(jié)構(gòu)賦值
let [first, ...rest] = [1, 2, 3, 4];
console.log(first); // outputs 1
console.log(rest); // outputs [ 2, 3, 4 ]
// 展開
let first = [1, 2];
let second = [3, 4];
let bothPlus = [0, ...first, ...second, 5];
// 對象的結(jié)構(gòu)賦值
let o = {
    a: "foo",
    b: 12,
    c: "bar"
};
let { a, b } = o;
// 屬性重命名
let { a: newName1, b: newName2 } = o;

結(jié)構(gòu)賦值同樣適用于函數(shù)聲明

type C = { a: string, b?: number }
function f({ a, b }: C): void {
    // ...
}

函數(shù)類型
函數(shù)聲明

function sum(x: number, y: number): number {
    return x + y;
}
// 輸入多余的(或者少于要求的)參數(shù),是不被允許的
sum(1, 2, 3); // error
sum(1); // error

函數(shù)表達(dá)式

let mySum = function (x: number, y: number): number {
    return x + y;
};
// 等價(jià)于
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y;
};
// 注意不要混淆了 TypeScript 中的 => 和 ES6 中的 =>悉罕。
// 在 TypeScript 的類型定義中赤屋,=> 用來表示函數(shù)的定義,左邊是輸入類型蛮粮,需要用括號括起來益缎,右邊是輸出類型。
// 在 ES6 中然想,=> 叫做箭頭函數(shù)

可選參數(shù)

function buildName(x: string, y?: string): string {
    if (y) {
        return `${x}${y}`;
    } else {
        return x;
    }
}

注意莺奔,可選參數(shù)必須接在必需參數(shù)后面。換句話說变泄,可選參數(shù)后面不允許再出現(xiàn)必須參數(shù)了
參數(shù)默認(rèn)值

function buildName(x: string, y: string = 'Cat') {
    return `${x}${y}`;
}

剩余參數(shù)

function push(array: any[], ...items: any[]) {
    items.forEach(function(item) {
        array.push(item);
    });
}

重載
重載允許一個(gè)函數(shù)接受不同數(shù)量或類型的參數(shù)時(shí)令哟,作出不同的處理;
比如妨蛹,我們需要實(shí)現(xiàn)一個(gè)函數(shù) reverse屏富,輸入數(shù)字 123 的時(shí)候,輸出反轉(zhuǎn)的數(shù)字 321蛙卤,輸入字符串 'hello' 的時(shí)候狠半,輸出反轉(zhuǎn)的字符串 'olleh'。

// 利用聯(lián)合類型颤难,我們可以這么實(shí)現(xiàn)
function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

然而這樣有一個(gè)缺點(diǎn)神年,就是不能夠精確的表達(dá),輸入為數(shù)字的時(shí)候行嗤,輸出也應(yīng)該為數(shù)字已日,輸入為字符串的時(shí)候,輸出也應(yīng)該為字符串栅屏。

這時(shí)飘千,我們可以使用重載定義多個(gè) reverse 的函數(shù)類型

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

我們重復(fù)定義了多次函數(shù) reverse堂鲜,前幾次都是函數(shù)定義,最后一次是函數(shù)實(shí)現(xiàn)护奈。在編輯器的代碼提示中缔莲,可以正確的看到前兩個(gè)提示。

注意霉旗,TypeScript 會優(yōu)先從最前面的函數(shù)定義開始匹配酌予,所以多個(gè)函數(shù)定義如果有包含關(guān)系,需要優(yōu)先把精確的定義寫在前面奖慌。

接口Interfaces

對行為的抽象,接口一般首字母大寫松靡。有的編程語言中會建議接口的名稱加上 I 前綴

interface Person {
    name: string;
    age: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25
};
// 定義的變量比接口少了一些屬性是不允許的
let tom: Person = {
    name: 'Tom'
};
// 多一些屬性也是不允許的
let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};

可見简僧,賦值的時(shí)候,變量的形狀必須和接口的形狀保持一致雕欺。
注意岛马,類型檢查器不會去檢查屬性的順序,只要相應(yīng)的屬性存在并且類型也是對的就可以;
有時(shí)我們希望不要完全匹配一個(gè)形狀屠列,那么可以用可選屬性:
可選屬性

interface Person {
    name: string;
    age?: number;
}
// ok
let tom: Person = {
    name: 'Tom'
};
// ok
let tom: Person = {
    name: 'Tom',
    age: 25
};
// oh no 這時(shí)仍然不允許添加未定義的屬性
let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};
  • 對可能存在的屬性進(jìn)行預(yù)定義
  • 捕獲引用了不存在的屬性時(shí)的錯(cuò)誤
    任意屬性
    需要注意的是啦逆,一旦定義了任意屬性,那么確定屬性和可選屬性都必須是它的子屬性
interface Person {
    name: string;
    age?: number;
    [propName: string]: any;
}
// ok
let tom: Person = {
    name: 'Tom',
    gender: 'male'
};
// not ok 
let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};
// 任意屬性的值允許是 string笛洛,但是可選屬性 age 的值卻是 number夏志,number 不是 string 的子屬性,所以報(bào)錯(cuò)了苛让。

只讀屬性

interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}
let tom: Person = {
    id: 89757,
    name: 'Tom',
    gender: 'male'
};
tom.id = 9527; // Cannot assign to 'id' because it is a constant or a read-only property.

注意:只讀的約束存在于第一次給對象賦值的時(shí)候沟蔑,而不是第一次給只讀屬性賦值的時(shí)候

interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

let tom: Person = {
    name: 'Tom',
    gender: 'male'
};
// ok
tom.id = 89757;

TypeScript具有ReadonlyArray<T>類型,它與Array<T>相似狱杰,只是把所有可變方法去掉了瘦材,因此可以確保數(shù)組創(chuàng)建后再也不能被修改:

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!

readonly vs const
最簡單判斷該用readonly還是const的方法是看要把它做為變量使用還是做為一個(gè)屬性。 做為變量使用的話用 const仿畸,若做為屬性則使用readonly食棕。
函數(shù)類型

interface SearchFunc {
  (source: string, subString: string): boolean;
}

對于函數(shù)類型的類型檢查來說,函數(shù)的參數(shù)名不需要與接口里定義的名字相匹配

let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
  let result = src.search(sub);
  return result > -1;
}

函數(shù)的參數(shù)會逐個(gè)進(jìn)行檢查错沽,要求對應(yīng)位置上的參數(shù)類型是兼容的簿晓。 如果你不想指定類型,TypeScript的類型系統(tǒng)會推斷出參數(shù)類型甥捺,因?yàn)楹瘮?shù)直接賦值給了 SearchFunc類型變量抢蚀。 函數(shù)的返回值類型是通過其返回值推斷出來的(此例是 false和true)。 如果讓這個(gè)函數(shù)返回?cái)?shù)字或字符串镰禾,類型檢查器會警告我們函數(shù)的返回值類型與 SearchFunc接口中的定義不匹配皿曲。

let mySearch: SearchFunc;
mySearch = function(src, sub) {
    let result = src.search(sub);
    return result > -1;
}

可索引的類型
支持兩種索引簽名:字符串和數(shù)字唱逢。
可以同時(shí)使用兩種類型的索引,但是數(shù)字索引的返回值必須是字符串索引返回值類型的子類型屋休。 這是因?yàn)楫?dāng)使用 number來索引時(shí)坞古,JavaScript會將它轉(zhuǎn)換成string然后再去索引對象。 也就是說用 100(一個(gè)number)去索引等同于使用"100"(一個(gè)string)去索引劫樟,因此兩者需要保持一致

interface NumberArray {
    [index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
// NumberArray 表示:只要 index 的類型是 number痪枫,那么值的類型必須是 number
interface ReadonlyStringArray {
    readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!

類類型
繼承接口
一個(gè)接口可以繼承多個(gè)接口,創(chuàng)建出多個(gè)接口的合成接口

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;

混合類型
可以同時(shí)具有上面提到的多種類型叠艳。

interface Counter {
    (start: number): string;
    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;

接口繼承類
參考文檔:TS官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奶陈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子附较,更是在濱河造成了極大的恐慌吃粒,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拒课,死亡現(xiàn)場離奇詭異徐勃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)早像,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門僻肖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人卢鹦,你說我怎么就攤上這事臀脏。” “怎么了冀自?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵谁榜,是天一觀的道長。 經(jīng)常有香客問我凡纳,道長窃植,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任荐糜,我火速辦了婚禮巷怜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘暴氏。我一直安慰自己延塑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布答渔。 她就那樣靜靜地躺著关带,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宋雏,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天芜飘,我揣著相機(jī)與錄音,去河邊找鬼磨总。 笑死嗦明,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚪燕。 我是一名探鬼主播娶牌,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼馆纳!你這毒婦竟也來了诗良?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤鲁驶,失蹤者是張志新(化名)和其女友劉穎累榜,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灵嫌,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年葛作,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寿羞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赂蠢,死狀恐怖绪穆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情虱岂,我是刑警寧澤玖院,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站第岖,受9級特大地震影響难菌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔑滓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一郊酒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧键袱,春花似錦燎窘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至澜汤,卻和暖如春蚜迅,著一層夾襖步出監(jiān)牢的瞬間舵匾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工慢叨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纽匙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓拍谐,卻偏偏與公主長得像烛缔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子轩拨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容