十分鐘,輕松入門 Typescript

Typescript 的最大優(yōu)點,就是 類型檢查強(qiáng)制約束。它可以讓我們在編譯運行代碼之前,就避免一些類型使用不當(dāng)、或者沒有按照規(guī)定書寫代碼而引起的各種錯誤。

類型檢查器(類型注解 Flow)

記住,TypeScript 的類型檢查器,一般設(shè)置于你要進(jìn)行檢查的事物的冒號后面。冒號后面,則是你要定義的檢查器格式。

原始類型

在 ES6 以后,Javascript 的原始類型一共有 6 種。在 Typescript 中,原始類型也是 6 種,它們分別是:

// 字符串類型
const a: string = "hello world";

// 數(shù)字類型
const b: number = 123;

// 布爾類型
const c: boolean = true;

// 空類型
const d: null = null;

// undefined 類型
const e: void = undefined;

// symbol 類型
const f: symbol = Symbol();

引用類型

數(shù)組類型

在 Typescript 中,定義數(shù)組我們有 3 種方式。分別是:

// Array<類型>,尖括號單一類型定義
const arr1: Array<number> = [1, 2, 3];

// 類型[],中括號單一類型定義
const arr2: number[] = [1, 2, 3];

// [類型,類型,類型],中括號多類型定義
const arr3: [string, number, number] = ["1", 2, 3];
對象類型

在 Typescript 中,定義對象的方式有多種,例如:

// object 類型檢查器(支持所有“對象”)
const person: object = function(){}

// 大括號 類型檢查器(支持特定類型)
const person: { 
  name: string; 
  age?: number // ? 代表該字段為可選,在對象中不一定要包含此屬性
} = { 
  name: "steve",
  age: 20 
};

如果我們不想使用這么繁瑣的 對象類型 定義方式,我們還可以使用 Type 來定義一個類型檢查器:

// 定義類型檢查器 Person
type Person = {
  name: string;
  age?: number; // ? 代表該字段為可選,在對象中不一定要包含此屬性
};

// 在常量名 冒號 后面使用類型檢查器 Person
const person:Person= {
  name: "steve",  // 該字段必須定義
  // age: 23,   // 該字段可以不定義
};
函數(shù)類型檢查器
  • 定義 回調(diào)函數(shù) 類型檢查器
const say = (callback: (a: string, b: number) => void) => {
  callback("1", 2);
};
say((str, number) => {
  console.log(str, number);
});
  • 定義 普通函數(shù) 類型檢查器
// 參數(shù)
function square(n: number) {
  return n + 1;
}

// 返回值
function square(n: number): number {
  return n + 1;
}

// 無返回值
function say(): void {
  console.log('hello world')
}

// 這里的 rest 可以使用任意名稱,目的為函數(shù)增添任意參數(shù)
const fn = (a: string, b: string, ...rest: number[]): string => {
  let str = a + b + rest;
  console.log(rest);
  console.log(str);
  return str;
};

fn("hello", "world", 1, 2, 3, 4, 5);
或類型檢查器
const str: "hello" | "world" | "balala" = "balala";
type StrType = number | string | Array<any>;

斷言 asserts

const nums = [1, 2, 3, 4, 5];
const res = nums.find((item) => item > 3);
// 寫法一:
const num1 = res as number
// 寫法二:
const num2 = <number>res    // jsx 下不能這么使用,會沖突

斷言的作用是啥呢?

interface Cat {
    name: string;
    run(): void;
}
interface Fish {
    name: string;
    swim(): void;
}

function isFish(animal: Cat | Fish) {
    // 如果不寫 animal as Fish,那么我們傳 Cat 類型的實例到 isFish,就會報錯
    if (typeof (animal as Fish).swim === 'function') {
       console.log(true);
    }
    console.log(false);
}

類型斷言只能夠欺騙 TS 編譯器,無法避免運行時的錯誤,反而濫用類型斷言可能會導(dǎo)致運行時錯誤。例如:

interface Cat {
    name: string;
    run(): void;
}
interface Fish {
    name: string;
    swim(): void;
}

function swim(animal: Cat | Fish) {
    (animal as Fish).swim();
}

const tom: Cat = {
    name: 'Tom',
    run() { console.log('run') }
};
swim(tom);

編譯時不會報錯,但在運行時會報錯 Uncaught TypeError: animal.swim is not a function`,所以,不要輕易使用斷言。

接口類型檢查器(interface)
  1. 普通 接口類型檢查器 定義
   interface Person {
     name: string;
     age: number;
     sex?: string;  // 可選
     readonly summary: string;  // 關(guān)鍵字 readonly,可以使該屬性成為只讀屬性
   }
   
   const person: Person = { name: "steve", age: 20, summary: "balala" };
   
   function printPerson(person: Person) {
     console.log(person.name);
     console.log(person.age);
     console.log(person.sex);
     // 報錯:Cannot assign to 'summary' because it is a read-only property.
     person.summary = "lalala";  // summary 為只讀屬性,  
   }
  1. 動態(tài) 接口類型檢查器 定義
  interface State {
    page: number; // 頁碼
    total: number; // 總數(shù)
    // 這里的 string,代表這個鍵可以定義的類型
    [key: string]: number; // 每頁條數(shù)
  }

  const state:State = {
    page: 1,
    total: 100,
    pageSize: 30
  }
類 class
  1. 聲明一個類
   // 定義 Person 類
   class Person {
     name: string; // this.name
     // private,無法使用實例直接訪問
     private age: number;
     // protected,只能在本 class 和子類 class 中才能訪問
     // readonly,在實例只能被讀取,無法被賦值
     protected readonly gender: boolean;
   
     // 構(gòu)造器,為 實例屬性 進(jìn)行賦值
     constructor(name: string, age: number) {
       this.name = name;
       this.age = age;
       this.gender = true 
     }
   
     // 定義實例方法
     sayHi(msg: string): void {
       console.log(`I am ${this.name}, ${msg}`);
     }
   }
   
   // 定義 Student 類,使用 extends 進(jìn)行繼承
   class Student extends Person {
     private constructor(name: string, age: number) {
       // 繼承父類的 實例屬性
       super(name, age);
       console.log(this.gender);
     }
   
     // 定義 靜態(tài)方法,直接使用 類名 進(jìn)行調(diào)用
     static create(name: string, age: number) {
       return new Student(name, age);
     }
   }
   
   const tom = new Person("tom", 18);
   console.log(tom.name);   // √ name 默認(rèn)為公有屬性(也可以添加 public 修飾符),可以被訪問
   console.log(tom.age);    // X 報錯,age 為私有屬性,除了類中,無法被外界訪問
   console.log(tom.gender); // X 報錯,gender 為保護(hù)屬性,只能在本類和子類中訪問,無法被外界訪問
   
   // X 報錯,因為 Student 的 constructor 為 private,故不能被創(chuàng)建
   const jack = new Student("steve", 25);
   const jack = Student.create("jack", 18);
  1. class 的接口(interface)

定義類的接口,可以確定在類中需要定義哪些屬性和方法。

   interface EatAndRun {
     eat(food: string): void;
     run(distance: number): void;
   }
   // 使用 EatAndRun 實現(xiàn)了 Person 類
   class Person implements EatAndRun {
     // 該類中定義了 eat 方法
     eat(food: string): void {
       console.log(`吃東西:${food}`);
     }
     // 該類中定義了 run 方法
     run(distance: number) {
       console.log(`直立行走:${distance}`);
     }
   }
   
   // 使用 EatAndRun 實現(xiàn)了 Animal 類
   class Animal implements EatAndRun {
     // 該類中定義了 eat 方法
     eat(food: string): void {
       console.log(`進(jìn)食:${food}`);
     }
     // 該類中定義了 run 方法
     run(distance: number) {
       console.log(`爬行:${distance}`);
       return 1;
     }
   }
  1. 抽象類

使用 abstract 修飾詞修飾的類,被叫做抽象類。使用 abstract 修飾詞修飾的方法,叫做抽象方法。

抽象類不能直接使用(無法 new 出實例),一定要被繼承,然后使用繼承類。

// 定義一個動物抽象類
abstract class Animal {
  eat(food: string): void {
    console.log(`狗狗吃了一塊:${food}`);
  }
  // 抽象方法在繼承的時候一定要被重寫
  abstract run(distance: number): void;
}
// 我們定義一個 Dog 類,繼承自 Animal 抽象類
class Dog extends Animal {
  // 抽象方法,一定要被重寫
  run(distance: number): void {
    console.log(`狗狗跑了${distance}公里`)
  }
}

const dog = new Dog();

dog.eat('骨頭');  // "狗狗吃了一塊:骨頭" 
dog.run(1); // "狗狗跑了1公里" 
interface 和 type 的區(qū)別

一般來說,interface(接口) 和 type(類型別名) 可以混用,但是也存在一些差異。

1. 對象/函數(shù)

兩者都可以用來描述對象的形狀或函數(shù)簽名,但語法不同。

interface,一般來說 name 后面直接寫 花括號:

// 約束對象
interface Point {
  x: number;
  y: number;
}

// 約束函數(shù)
interface SetPoint {
  (x: number, y: number): void;
}

type,一般來說 name 后面都是接 等號:

// 約束對象
type Point = {
  x: number;
  y: number;
};

// 約束函數(shù)
type SetPoint = (x: number, y: number) => void;

2. 其他類型

與 interface 不同,type 也可用于其他類型,例如 原始類型、聯(lián)合類型和數(shù)組類型。

// 原始類型
type Name = string;

// 對象類型
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };

// union類型
type PartialPoint = PartialPointX | PartialPointY;

// 數(shù)組類型
type Data = [number, string];

3. 擴(kuò)展

兩者都可以進(jìn)行擴(kuò)展,但同樣語法不同。此外,請注意 interface 和 type 不是相互排斥的。interface 可以擴(kuò)展 type,反之亦然。

// 接口擴(kuò)展接口
interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }

//類型別名擴(kuò)展類型別名
type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };

// 接口擴(kuò)展類型別名
type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }

// 類型別名擴(kuò)展接口
interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };

4. 聲明合并

與類型別名不同,接口可以定義多次,并將被視為單個接口(所有聲明的成員都被合并)。

// These two declarations become:
// interface Point { x: number; y: number; }
interface Point { x: number; }
interface Point { y: number; }

const point: Point = { x: 1, y: 2 };

泛型

什么是泛型?

當(dāng)我們在使用函數(shù)之前,不知道函數(shù)內(nèi)部具體需要什么類型的 數(shù)據(jù) 的時候,可以在 使用的時候 動態(tài)設(shè)置。泛型,就是這樣的一種寫法。

// 在使用之前不知道函數(shù)內(nèi)部需要什么類型,可以在使用的時候動態(tài)設(shè)置
function createArray<T>(length: number, value: T): T[] {
  const arr = Array<T>(length).fill(value);
  return arr;
}

// 我們在這里進(jìn)行函數(shù)調(diào)用,調(diào)用的時候就對傳參類型進(jìn)行了設(shè)置
const res = createArray<string>(10, 'hello');
console.log(res);

枚舉類型

枚舉可以實現(xiàn) 數(shù)字類型自增長

定義枚舉類型:

enum En {
  a = 3,    // 3
  b,        // 4
  c,        // 5
}

// 獲取枚舉值
En.a        // 3
En['a']     // 3

// 根據(jù)枚舉值,獲取枚舉鍵
En[3]       // a,值為 3 的 enum 元素 name

在枚舉中,除開數(shù)字之外的其他任何類型都無法實現(xiàn) 自增長,一定要全部定義,不然 就會報錯。

enum En{
  a = 'say',    // say
  b = 'hello',  // hello
  c = 'world',  // world,這里一定要定義
}

En.a        // say
En['a']     // say
En['say']   // undefined
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容