TypeScript的數(shù)據(jù)類型

TypeScipt中為了使編寫的代碼更加規(guī)范盅安,更有利于維護(hù),增加了類型校驗(yàn)世囊,所以以后寫ts代碼必須要指定類型

TypeScript后面可以不指定類型别瞭,但是后期不能改變其類型,不然會報(bào)錯(cuò)株憾,但是只會報(bào)錯(cuò)蝙寨,不會阻止代碼編譯,因?yàn)?code>JS是可以允許的


1. 基本類型

1.1 布爾類型(boolean)

let flag: boolean = true;
flag = 123; // 報(bào)錯(cuò),因?yàn)椴环项愋?flag = false; // 正確寫法,boolean類型只能寫 true 和 false

1.2 數(shù)字類型(number)

let num: number = 123;
console.log(num);

1.3 字符串類型(string)

let str: string = "string";
console.log(str);

1.4 數(shù)組類型(Array)

TypeScript中有兩種定義數(shù)組的方法

// 第一種定義數(shù)組方法
let arr1: number[] = [1.2.3]; // 一個(gè)全是數(shù)字的數(shù)組

// 第二種定義數(shù)組方法
let arr2: Array<number> = [1,2,3];

1.5 只讀數(shù)組類型(ReadonlyArray)

只讀數(shù)組中的數(shù)組成員和數(shù)組本身的長度等屬性都不能夠修改嗤瞎,并且也不能賦值給原賦值的數(shù)組

let a: number[] = [1,2,3,4];
let ro: ReadonlyArray<number> = a; // 其實(shí)只讀數(shù)組只是一個(gè)內(nèi)置定義的泛型接口
ro[1] = 5; // 報(bào)錯(cuò)
ro.length = 5; // 報(bào)錯(cuò)
a = ro; // 報(bào)錯(cuò),因?yàn)閞o的類型為Readonly,已經(jīng)改變了類型
a = ro as number[]; // 正確,不能通過上面的方法復(fù)制,但是可以通過類型斷言的方式

類型斷言見此鏈接

1.6 元組類型(tuple)

元組類型屬于數(shù)組的一種墙歪,上面一種數(shù)組里面只能有一種類型,否則會報(bào)錯(cuò)贝奇,而元組類型內(nèi)部可以有多種類型

// 元組類型可以為數(shù)組中的每個(gè)成員指定一個(gè)對應(yīng)的類型
let arr: [number,string] = [123,"string"]; // 注意如果類型不對應(yīng)也會報(bào)錯(cuò)
arr[2] = 456; // 報(bào)錯(cuò)
// 因?yàn)樵M類型在聲明時(shí)是一一對應(yīng)的,這里只能有2個(gè)成員

1.7 枚舉類型(enum)

/*
  通過:
    enum 枚舉名{
      標(biāo)識符 = 整形常數(shù),
      標(biāo)識符 = 整形常數(shù),
      ......
      標(biāo)識符 = 整形常數(shù)
    };
    定義一個(gè)枚舉類型
*/
enum Color {
  Red = 1,
  Blue = 3,
  Oragne = 5
}

let color: Color = Color.Red; // color為Color枚舉類型,值為Color中的Red,也就是1
console.log(color); // 1

注意:

  • 如果沒有給標(biāo)識符賦值虹菲,那么標(biāo)識符的值默認(rèn)為索引值
  • 如果在期間給某個(gè)標(biāo)識符進(jìn)行了賦值,而之后的標(biāo)識符沒有賦值掉瞳,那么之后表示符的索引依次為前面的值加1
  • 可以把標(biāo)識符用引號括起來毕源,效果不受影響
  • 還可以通過反過來選擇索引值來獲取字符串標(biāo)識符
enum Color {
  Red,
  Blue = 3,
  "Oragne"
}

let color1: Color = Color.Red;
let color2: Color = Color.Blue;
let color3: Color = Color.Oragne;
let color4: string = Color[0]; // 通過獲取索引得到標(biāo)識符

console.log(color1); // 0
console.log(color2); // 3
console.log(color3); // 4
console.log(color4); // red

1.8 任意類型(any)

任意類型的數(shù)據(jù)就像JS一樣,可以隨意改變其類型

let num:any = 123;
num = "string";
console.log(num); // string

具體用法

// 如果在ts中想要獲取 DOM 節(jié)點(diǎn),就需要使用任意類型
let oDiv: any = document.getElementsByTagName("div")[0];
oDiv.style.backgroundColor = "red";
// 按道理說DOM節(jié)點(diǎn)應(yīng)該是個(gè)對象,但是TypeScript中沒有對象的基本類型,所以必須使用 any 類型才不會報(bào)錯(cuò)

1.9 undefinednull類型

雖然為變量指定了類型陕习,但是如果不賦值的話默認(rèn)該變量還是undefined類型脑豹,如果沒有指定undefined直接使用該變量的話會報(bào)錯(cuò),只有自己指定的是undefined類型才不會報(bào)錯(cuò)

let flag1: undefined; // 也可以 let flag1: undefined = undefined;
console.log(flag); // undefined

let flag2: null = null; // 如果不指定值為null那么打印的時(shí)候會報(bào)錯(cuò)
console.log(flag2); // null

為變量指定多種可能的類型

let flag: number | undefined; // 這種寫法就不會在沒有賦值的時(shí)候報(bào)錯(cuò)了,因?yàn)樵O(shè)置了可能為undefined
console.log(flag); // undefined
flag = 123;
console.log(flag); // 123 也可以改為數(shù)值類型

// 也可以設(shè)定多個(gè)類型
let flag1: number | string | null | undefined;
flag1 = 123;
console.log(flag1); // 123
flag1 = null;
console.log(flag1); // null
flag1 = "string";
console.log(flag1); // string

1.10 void類型

TypeScript中的void表示沒有任何類型衡查,一般用于定義方法的時(shí)候沒有返回值瘩欺,雖然也能給變量指定類型,但是void類型只能被賦值undefinednull拌牲,沒有什么實(shí)際意義

TypeScript中函數(shù)的類型表示其返回值的類型俱饿,函數(shù)類型為void表示其沒有返回值

function run(): void {
  console.log(123);
  // return 不能有返回值,否則報(bào)錯(cuò)
}

function run1(): number {
  console.log(456);
  return 123; // 必須有返回值,并且返回值為number類型,否則報(bào)錯(cuò)
}

function run2(): any {
  console.log(789); // 因?yàn)閍ny是任意類型,所以也可以不要返回值
}

1.11 never類型

never類型是其他類型(包括nullundefine)的子類型,代表著從來不會出現(xiàn)的值塌忽,意味著聲明never類型的變量只能被never類型所賦值

let a: undefined;
a = undefined;

let b: null;
b = null;

let c: never; // c不能被任何值賦值,包括 null 和 undefiend
c = (() => {
  throw new Error("error!!");
})(); // 可以這樣賦值

// 返回never的函數(shù)必須存在無法達(dá)到的終點(diǎn)
function error(message: string): never {
  throw new Error(message);
}
// 返回never的函數(shù)必須存在無法達(dá)到的終點(diǎn)
function infiniteLoop(): never {
  while (true) {
  }
}

// 推斷的返回值類型為never
function fail() {
  return error("Something failed");
}

1.12 object類型

object表示非原始類型拍埠,也就是除numberstring土居,boolean枣购,symbol嬉探,nullundefined之外的類型

let stu: object = {name:"張三", age:18};
console.log(stu); // {name: "張三", age: 18}

// 也可以
let stu: {} = { name: "張三", age: 18 };
console.log(stu); // {name: "張三", age: 18}
declare function create (o: object | null): void;
// declare是一個(gè)聲明的關(guān)鍵字,可以寫在聲明一個(gè)變量時(shí)解決命名沖突的問題
create({ prop: 0 }); // OK
create(null); // OK

create(42); // 報(bào)錯(cuò)
create("string"); // 報(bào)錯(cuò)
create(false); // 報(bào)錯(cuò)
create(undefined); // 報(bào)錯(cuò)

2. 高級類型

2.1 交叉類型

交叉類型是將多個(gè)類型合并為一個(gè)類型。這讓我們可以把現(xiàn)有的多種類型疊加到一起成為一種類型棉圈,它包含了所需的所有類型的特性

function extend<T, U>(first: T, second: U): T & U {
  let result = <any>{}; // 官方這里是T&U,但是會報(bào)錯(cuò),因?yàn)椴恢猅和U是不是對象,必須any才可以

  for (let id in first) {
    (<any>result)[id] = (<any>first)[id];
  }
  for (let id in second) {
    if (!result.hasOwnProperty(id)) {
      (<any>result)[id] = (<any>second)[id];
    }
  }

  return result;
}

class Person {
  constructor(public name: string) { }
}
interface Loggable {
  log(): void;
}
class ConsoleLogger implements Loggable {
  log() {
    // ...
  }
}

var jim = extend(new Person("Jim"), new ConsoleLogger());
var n = jim.name;
jim.log();

2.2 聯(lián)合類型

聯(lián)合類型與交叉類型很有關(guān)聯(lián)涩堤,但是使用上卻完全不同,我們使用的用豎線隔開每一個(gè)類型參數(shù)的時(shí)候使用的就是聯(lián)合類型

聯(lián)合類型表示一個(gè)值可以是幾種類型之一分瘾。 用豎線( |)分隔每個(gè)類型胎围,所以 number | string | boolean表示一個(gè)值可以是 numberstring德召,或 boolean

function padLeft(value: string, padding: string | number) {
  // ...
}

let indentedString = padLeft("Hello world", true); // errors,只能是string 或 number

如果一個(gè)值是聯(lián)合類型白魂,我們只能訪問此聯(lián)合類型的所有類型里共有的成員

interface Bird {
  fly();
  layEggs();
}

interface Fish {
  swim();
  layEggs();
}

function getSmallPet(): Fish | Bird { // 這的報(bào)錯(cuò)先不管
  // ...
}

let pet = getSmallPet(); // 因?yàn)闆]有明確返回哪個(gè)類型,所以只能確定時(shí)Fish和Bird類型中的一個(gè)
pet.layEggs(); // 我們可以調(diào)用共有的方法
pet.swim();    // errors,不能調(diào)用一個(gè)類型的方法,因?yàn)槿f一是Bird類型就不行了

2.3 類型保護(hù)

聯(lián)合類型適合于那些值可以為不同類型的情況。 但當(dāng)我們想確切地了解是否為 Fish時(shí)上岗,JavaScript里常用來區(qū)分2個(gè)可能值的方法是檢查成員是否存在福荸,但是在TypeScript中必須要先使用類型斷言

let pet = getSmallPet();

if ((<Fish>pet).swim) {
  (<Fish>pet).swim();
} else {
  (<Bird>pet).fly();
}
2.3.1 用戶自定義類型保護(hù)
function isFish(pet: Fish | Bird): pet is Fish {
  return (<Fish>pet).swim !== undefined; // 返回一個(gè)布爾值,然后TypeScript會縮減該變量類型
}
/*
  pet is Fish就是類型謂詞。謂詞為 parameterName is Type 這種形式肴掷,parameterName必須是來自于當(dāng)前函數(shù)簽名里的一個(gè)參數(shù)名
*/
// 'swim' 和 'fly' 調(diào)用都沒有問題了,因?yàn)榭s減了pet的類型
if (isFish(pet)) {
  pet.swim();
} else {
  pet.fly();
}

TypeScript不僅知道在 if分支里 petFish類型敬锐,它還清楚在 else分支里,一定 不是 Fish類型捆等,一定是 Bird類型

2.3.2 typeof類型保護(hù)
function padLeft(value: string, padding: string | number) {
  if (typeof padding === "number") {
    return Array(padding + 1).join(" ") + value;
  }
  if (typeof padding === "string") {
    return padding + value;
  }
    
  throw new Error(`Expected string or number, got '${padding}'.`);
}

這些 typeof類型保護(hù)只有兩種形式能被識別:typeof v === "typename"typeof v !== "typename""typename"必須是 "number"续室, "string"栋烤, "boolean""symbol"。 但是TypeScript并不會阻止你與其它字符串比較,語言不會把那些表達(dá)式識別為類型保護(hù)

2.3.3 instanceof類型保護(hù)
interface Padder {
  getPaddingString(): string
}

class SpaceRepeatingPadder implements Padder {
  constructor(private numSpaces: number) { }
  getPaddingString() {
    return Array(this.numSpaces + 1).join(" ");
  }
}

class StringPadder implements Padder {
  constructor(private value: string) { }
  getPaddingString() {
    return this.value;
  }
}

function getRandomPadder() {
  return Math.random() < 0.5
    ? new SpaceRepeatingPadder(4)
    : new StringPadder(" ");
}

// 類型為SpaceRepeatingPadder | StringPadder
let padder: Padder = getRandomPadder();

if (padder instanceof SpaceRepeatingPadder) {
  padder; // 類型細(xì)化為'SpaceRepeatingPadder'
}
if (padder instanceof StringPadder) {
  padder; // 類型細(xì)化為'StringPadder'
}

instanceof的右側(cè)要求是一個(gè)構(gòu)造函數(shù)挺狰,TypeScript將細(xì)化為:

  • 此構(gòu)造函數(shù)的 prototype屬性的類型明郭,如果它的類型不為 any的話
  • 構(gòu)造簽名所返回的類型的聯(lián)合
2.3.4 可以為null的類型

如果沒有在vscode中,直接編譯的話是可以給一個(gè)其他類型的值賦值為undefined或者null的丰泊,但是如果編譯時(shí)使用了--strictNullChecks標(biāo)記的話薯定,就會和vscode一樣不能賦值了,并且可選參數(shù)和可以選屬性會自動(dòng)加上| undefined類型

2.3.5 類型保護(hù)與類型斷言

由于可以為null的類型是通過聯(lián)合類型實(shí)現(xiàn)瞳购,那么需要使用類型保護(hù)來去除 null

function f(sn: string | null): string {
  if (sn === null) {
    return "default";
  } else {
    return sn;
  }
}

// 也可以使用下面的形式
function f(sn: string | null): string {
  return sn || "default";
}

如果編譯器不能夠去除 nullundefined话侄,你可以使用類型斷言手動(dòng)去除。 語法是添加 !后綴:identifier!identifier的類型里去除了 nullundefined

function broken(name: string | null): string {
  function postfix(epithet: string) {
    return name.charAt(0) + '.  the ' + epithet; // error, 'name' is possibly null
  }
  name = name || "Bob";

  return postfix("great");
}

// 上面的函數(shù)會報(bào)錯(cuò)
function fixed(name: string | null): string {
  function postfix(epithet: string) {
    // 這里的name強(qiáng)制斷言不是null或者undefined,因?yàn)樵谇短缀瘮?shù)中不知道name是否為null
    return name!.charAt(0) + '.  the ' + epithet; // ok
  }
  name = name || "Bob"; // 這里已經(jīng)明確表明返回的name肯定是字符串
  
  return postfix("great"); // 但是由于是嵌套函數(shù),這里還不知道
}
/*
  嵌套函數(shù)中: 因?yàn)榫幾g器無法去除嵌套函數(shù)的null(除非是立即調(diào)用的函數(shù)表達(dá)式)学赛。因?yàn)樗鼰o法跟蹤所有對嵌套函數(shù)的調(diào)用,尤其是將內(nèi)層函數(shù)做為外層函數(shù)的返回值年堆。如果無法知道函數(shù)在哪里被調(diào)用,就無法知道調(diào)用時(shí)name的類型
*/

2.4 類型別名

類型別名會給一個(gè)類型起個(gè)新名字。類型別名有時(shí)和接口很像,但是可以作用于原始值盏浇,聯(lián)合類型变丧,元組以及其它任何需要手寫的類型

別名不會創(chuàng)建一個(gè)新的類型,而是創(chuàng)建了一個(gè)新的名字來引用那個(gè)類型

type Name = string; // 通過type關(guān)鍵詞創(chuàng)建一個(gè)別名
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
  if (typeof n === 'string') {
    return n;
  } else {
    return n();
  }
}

同接口一樣绢掰,類型別名也可以是泛型痒蓬,可以添加類型參數(shù)并且在別名聲明的右側(cè)傳入

type Container<T> = { value: T };

// 我們也可以使用類型別名來在屬性里引用自己
type Tree<T> = {
  value: T;
  left: Tree<T>;
  right: Tree<T>;
}

// 與交叉類型一起使用童擎,我們可以創(chuàng)建出一些十分稀奇古怪的類型
type LinkedList<T> = T & { next: LinkedList<T> };

interface Person {
  name: string;
}

var people: LinkedList<Person>;
var s = people.name; // 注意這種寫法在vscode中會報(bào)錯(cuò),因?yàn)楦訃?yán)格,必須先賦值再使用
var s = people.next.name;
var s = people.next.next.name;
var s = people.next.next.next.name;

類型別名不能出現(xiàn)在聲明右側(cè)的任何地方

type Yikes = Array<Yikes>; // 報(bào)錯(cuò)

2.5 字符串自變量類型

字符串字面量類型允許指定字符串必須的固定值。在實(shí)際應(yīng)用中攻晒,字符串字面量類型可以與聯(lián)合類型顾复、類型保護(hù)和類型別名很好的配合。通過結(jié)合使用這些特性炎辨,可以實(shí)現(xiàn)類似枚舉類型的字符串

type Easing = "ease-in" | "ease-out" | "ease-in-out";

class UIElement {
  animate(dx: number, dy: number, easing: Easing) {
    if (easing === "ease-in") {
      // ...
    } else if (easing === "ease-out") {
    } else if (easing === "ease-in-out") {
    } else {
      // error! should not pass null or undefined.
    }
  }
}

let button = new UIElement();
button.animate(0, 0, "ease-in");
button.animate(0, 0, "uneasy"); // error: "uneasy" is not allowed here
// 只能從三種允許的字符中選擇其一來做為參數(shù)傳遞,傳入其它值則會產(chǎn)生錯(cuò)誤

字符串字面量類型還可以用于區(qū)分函數(shù)重載

function createElement(tagName: "img"): HTMLImageElement;
function createElement(tagName: "input"): HTMLInputElement;
// ... more overloads ...
function createElement(tagName: string): Element {
  // ... code goes here ...
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捕透,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子碴萧,更是在濱河造成了極大的恐慌乙嘀,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件破喻,死亡現(xiàn)場離奇詭異虎谢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)曹质,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門婴噩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人羽德,你說我怎么就攤上這事几莽。” “怎么了宅静?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵章蚣,是天一觀的道長。 經(jīng)常有香客問我姨夹,道長纤垂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任磷账,我火速辦了婚禮峭沦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逃糟。我一直安慰自己吼鱼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布绰咽。 她就那樣靜靜地躺著蛉抓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪剃诅。 梳的紋絲不亂的頭發(fā)上巷送,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機(jī)與錄音矛辕,去河邊找鬼笑跛。 笑死付魔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的飞蹂。 我是一名探鬼主播几苍,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼陈哑!你這毒婦竟也來了妻坝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤惊窖,失蹤者是張志新(化名)和其女友劉穎刽宪,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體界酒,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡圣拄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了毁欣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庇谆。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖凭疮,靈堂內(nèi)的尸體忽然破棺而出饭耳,到底是詐尸還是另有隱情,我是刑警寧澤执解,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布寞肖,位于F島的核電站,受9級特大地震影響材鹦,放射性物質(zhì)發(fā)生泄漏逝淹。R本人自食惡果不足惜耕姊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一桶唐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧茉兰,春花似錦尤泽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至莫鸭,卻和暖如春闹丐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背被因。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工卿拴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衫仑,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓堕花,卻偏偏與公主長得像文狱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子缘挽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355