TS 進階

上篇: TS基礎數組

類型的別名 type

type strAria = string; // 給 string 類型定義了 strAria別名
const str: strAria = 'abc';

type fnAria = () => string;
function (callback:fnAria):void {
    callback();
}
複製代碼

字符串字面量類型

type EventName = 'xm' | 'xh' | 'xb';
const str : EventName = 'xb'
const elseStr : EventName = 'xf' // error, 不在這幾個名字當中
複製代碼

咱們使用 type 定了一個字符串字面量類型 EventNames,它只能取三種字符串中的一種。函數

注意,類型別名與字符串字面量類型都是使用 type 進行定義。post

元組

一個帶有不一樣值的數組ui

let confusion: [string,number] = ['a',1]; // 這就叫元組
複製代碼
let confusion: [string, number];
confusion[0] = 'a'; // 能夠只賦值給某一項
confusion[1] = 'b' // error , 元組的第2項必須爲 number

// 若是直接給元組賦值,要徹底提供其定義好的類型和長度
confusion = ['a',1]
複製代碼

越界的元素

當添加越界的元素時,它的類型會被限制爲元組中每一個類型的聯合類型:this

let xcatliu: [string, number];
xcatliu = ['Xcat Liu', 25]; // ok
xcatliu.push('http://xcatliu.com/'); // ok
xcatliu.push(true); // error, 不能添加非字符串和 number 的值
複製代碼

枚舉 Enum

用於定義一個類型的值在必定的範圍內spa

使用 enum 定義枚舉code

枚舉的成員從0開始遞增,而且key 和 value 會互相映射xml

enum Colors { Red, Yellow, Blue }
Colors['Red'] === 0 // true 從0開始遞增
Colors[0] === 'Red' // 相互映射

// 枚舉事實上會編譯成以下
var Color;
(function (Color) {
    Color[Color["Red"] = 0] = "Red";
    Color[Color["Yellow"] = 1] = "Yellow";
    Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));
複製代碼
  • 手動賦值

枚舉的值是能夠二次賦值的,被從新賦值的後一項會接着上一項的key遞增對象

若是兩個枚舉值重複了,不會報錯,可是值會被覆蓋繼承

能夠爲小數或者負數,遞增步數仍然爲 1

配合斷言,可讓枚舉不是數字

enum Colors { Red = 1, Yellow, Blue }
Colors['Red'] = 2 // 從新賦值
Colors['Yellow'] // 3 下一項 + 1

Colors['Yellow'] = 1 // 此時 Red 和 Blue 值重複了, Colors[2] 只會取最後的值,由於覆蓋了。
console.log(Colors[2] === "Red"); // false
console.log(Colors[2] === "Blue"); // true

// 負數
Colors['Red'] = 2.1
Colors['Yellow'] // 3.1
複製代碼
  • 斷言
enum Colors { Red = 1, Yellow, Blue = <any>"S" } Colors['Blue'] // 'S' 複製代碼

計算所得項

上面咱們使用的枚舉都是常數項

計算所得項就是經過計算賦值的枚舉,只在編譯階段求值

enum Colors { Red = 1, Yellow, Blue = 1 + 1 }

// 因爲編譯時求值 計算所得項的後一項若是沒有賦值,會由於沒法得到初始值報錯
enum Colors { Red = 'asdasd'.length, Yellow, Blue } // error 

複製代碼

當知足如下條件時,枚舉成員被看成是常數:

  • 不具備初始化函數而且以前的枚舉成員是常數(單純聲明的時候)。在這種狀況下,當前枚舉成員的值爲上一個枚舉成員的值加 1。但第一個枚舉元素是個例外。若是它沒有初始化方法,那麼它的初始值爲 0
  • 使用常數枚舉表達式初始化。常數枚舉表達式是 TypeScript 表達式的子集,它能夠在編譯階段求值。當一個表達式知足下面條件之一時,它就是一個常數枚舉表達式:
    • 數字字面量 => Red = 1
    • 引用以前定義的常數枚舉成員(能夠是在不一樣的枚舉類型中定義的)若是這個成員是在同一個枚舉類型中定義的,可使用非限定名來引用
    • 帶括號的常數枚舉表達式
    • +, -, ~ 一元運算符應用於常數枚舉表達式
    • +, -, *, /, %, <<, >>, >>>, &, |, ^ 二元運算符,常數枚舉表達式作爲其一個操做對象。若常數枚舉表達式求值後爲 NaN 或 Infinity,則會在編譯階段報錯

全部其它狀況的枚舉成員被看成是須要計算得出的值。

  • 被當成是常量的例子
enum Colors { Red, Yellow, Blue }
// Colors['Red'] ==> 0 Colors['Yellow'] ==> 1 Colors['Blue'] ==> 2

enum Directions { 
	Up = 996,
    Down = Up,
    Left = Colors['Red'],
    Right = (1 + 1),
    UpLeft = 2 % 1,
    DownLeft = 'a' - 1// 結果 NaN 報錯
}
複製代碼

常數枚舉

使用 const enum 定義的枚舉

常數枚舉與普通枚舉的區別是,它會在編譯階段被刪除,而且不能包含計算成員。

const enum Color {Red, Green, Blue = "blue".length};// error 不能包含計算成員
複製代碼

外部枚舉

使用 declare enum 定義的枚舉類型

declare 定義的類型只會用於編譯時的檢查,編譯結果中會被刪除。

外部枚舉與聲明語句同樣,常出如今聲明文件中。

同時使用 declareconst 也是能夠的:

類與接口 implements

類用於面向對象

接口用於對象形狀的描述

不一樣的類之間某一部分可能行爲一致,那麼爲了避免重複寫兩個同樣的接口,可使用implements 實現重用interface

implements 中文譯爲 "實現"

好比有個狗類,有個貓類,它們都有 eat 這個方法,實現的形狀一致

interface Behavior {
    eat(food: string): void
}

class Dog implements Behavior {
  eat(foot) {}    
}
class Cat implements Behavior {
  eat(foot) {}
}

class habaDog extends Dog implements Behavior {
  // 此時哈巴狗繼承了狗類,就有了 eat 方法 
}
複製代碼
  • 多個實現
interface Behavior { // 行爲接口
  eat(food: string): void
}

interface Appearance { // 外表接口
  fur:string
}

class Dog implements Behavior {
  eat(foot) {}    
}

class habaDog extends Dog implements Behavior, Appearance {
    fur = ''  
}
複製代碼

接口繼承

接口也是能夠繼承接口的

繼承老爸姓名

interface Fa {
  surname: string
}

interface Son extends Fa {
  name: string
}

const obj: Son = {
  surname : 'z',
  name: 'zc'
}
複製代碼

接口繼承class

用於將某個 class 定義爲類型,並往上再添加類型。

class Fa {
  constructor() {}
  suck(){

  }
}

interface Son extends Fa {
  suck():void;
  name: string;
}

複製代碼

泛型

指在定義函數、接口或類的時候,不預先指定具體的類型,而在使用的時候再指定類型的一種特性。

使用 <T> 表明類型的變量, T 只是約定用法,能夠任意指定。

function getArrVal<T>(something:T):Array<T> {
  return [something];
}

getArrVal<string>('z') // ['z'] 使用時再指定類型
getArrVal('z') // 不寫也沒事 ts 會推論出來

// 接口型定義
interface Test<T> {
  num : T
}
let o : Test<string> = {
  num: '1'
}
複製代碼
  • 能夠一次性定義多個泛型
interface Test<T,U> {
  name?: T,
  num : U
}
let o : Test<string,number> = {
  num: 1
}

function Test<T,U> (a:T,b:U):void { // 函數定義
  console.log(a,b);
  
}
Test<string,number>('1',1)
複製代碼

泛型約束

泛型沒法知道具體的類型,因此沒法操做它的屬性和方法

function Test<T> (a:T):void {
  console.log(a.length);  // error
}
Test<string>('1')
複製代碼

當你明確知道泛型中有哪些屬性方法時,能夠經過 extends 進行泛型約束,寫在聲明函數名的後面

interface hasLengthProp {
    length : number;
}
function Test<T extends hasLengthProp>(a:T):void {
    console.log(a.length);
}
複製代碼
  • 泛型能夠約束泛型

至關於泛型的繼承

function test<T extends U,U>(a:T,b:U):void {
    console.log(a);
}

test({a:1,b:2,c:3},{a:1,b:2})
複製代碼

泛型接口

在接口中定義泛型,若是接口中只定義了一個匿名函數的類型,直接賦值便可。

interface Test {
  <T>(name:T):void
}
let say:Test; // 直接賦值

say = function<T>(name:T):void {
  console.log(name);
}
say('haha')
複製代碼

若是接口中包含多個屬性,這個接口就是一個對象的描述

interface Test {
  demo<T>(name:T):void;
  a:string;
}
let say:Test; // 對象的描述

say.demo = function<T>(name:T):void {
  console.log(name);
}
say.demo('haha')
複製代碼

泛型類

就是在泛型裏面使用類型變量 類那節說過,類有兩部分:靜態部分和實例部分。 泛型類指的是實例部分的類型,因此類的靜態屬性不能使用這個泛型類型

class Name<T>{
  num:T;
  constructor(num:T) {
    this.num = num
  }
  add:(x:T,y:T) => T;
}
let addName = new Name<number>(10)
addName.num = 10
addName.add = (x:number,y:number) => {
  return 1+2
}
複製代碼

泛型默認值

當代碼中沒有直接指定,而且類型推論也沒有成功時,默認值會生效

function say<T = any>(name: T):void {
    alert(name)
}
say<string>('1') // ok
say(true) // ok
複製代碼

聲明合併

就是說聲明兩個一樣的接口、類或者函數,會進行合併操做。

合併的屬性的類型必須是惟一的

interface Alarm {
    price: number;
     alert(s: string): string;
}
interface Alarm {
    weight: number;
    alert(s: string, n: number): string;
}
===> 至關於
interface Alarm {
    price: number;
    weight: number;
   	alert(s: string, n: number): string;
}
複製代碼
相關文章
相關標籤/搜索