《TypeScript入門教程》筆記


基礎

布爾值

  let isDone: boolean = false;

數值

  let decLiteral: number = 6;

字符串

  let myName: string = 'tom';

無值

1.示例

  let myName: null = null;
  let myName: undefined = undefined;

2.null/undefined是所有類型的子類型

  let val: 其它類型 = undefined;

空值

1.關鍵字為void,只能被賦值undefined和null

  let unusable: void = undefined;

任意值

1.可以賦值為任意類型的值(沒有類型限制)

  let myFavoriteNumber: any = 'seven';
  myFavoriteNumber = 7;

2.對任意值進行任何操作,返回值類型都是任意值

3.變量聲明時,如果未指定類型

  a.未賦值,則會默認為any類型
    let something;
    something = 'seven';
    something = 7;
  b.賦值了,則會被類型推斷為所賦值的類型
    let myFavoriteNumber = 'seven';
    myFavoriteNumber = 7;  // 會報錯

聯合

1.表示取值可以為多種類型中的一種

2.示例

  let myFavoriteNumber: string | number
  myFavoriteNumber = 'seven'
  myFavoriteNumber = 7

3.當不確定聯合類型變量的類型時,只能訪問此聯合類型的所有類型里共有的屬性或方法

  function getString(something: string | number): string {
    return something.toString()
  }

對象

1.對象的類型由接口定義

2.接口是對行為的抽象,而具體實現則由類去實現

3.示例代碼

  interface Person {
    name: string
    age: number
  }
  
  let tom: Person = {
    name: 'Tom',
    age: 25
  }

4.對象定義時,變量的屬性數量/形狀必須和接口屬性數量/形狀保持一致

5.可選屬性

  interface Person {
    name: string
    age?: number
  }

  let tom: Person = {
    name: 'Tom'
  }

5.可索引屬性

  interface Person {
    name: number
    age?: number
    [propName: string]: string
  }
  // 報錯 - 確定屬性和可選屬性的返回值類型必須和它的返回值類型匹配,或者是它的返回值類型的子集

  class Animal {
    name: string;
  }
  class Dog extends Animal {
    breed: string;
  }
  // 錯誤 - 可索引的屬性可以多個,數字索引的返回值必須是字符串索引返回值類型的子類型
  interface NotOkay {
    [x: number]: Animal;
    [x: string]: Dog;
  }

6.只讀屬性

  interface Person {
    readonly id: number
    age: number
  }

  let tom: Person = {
    id: 10,
    age: 25
  }

  tom.id = 89757 // 報錯

數組

1.類型+方括號表示法

  let arr: number[] = [1, 1, 2, 3, 5];
  let arr: number[] = [1, 1, 2, 3, '5']; // 會報錯
  arr.push('5'); // 會報錯

2.數組泛型

  let fibonacci: Array<number> = [1, 1, 2, 3, 5]

3.接口表示數組

  interface NumberArray {
    [index: number]: number
  }
  let fibonacci: NumberArray = [1, 1, 2, 3, 5]

4.any數組

  • 用any表示數組中允許出現任意類型
  • 示例
  let list: any[] = ['xjh', 25, { key: 'xx' }]

5.類數組

  • a.常見的類數組都有自己的接口定義,如 IArguments, NodeList, HTMLCollection
  • b.示例
  function sum() {
    let args: IArguments = arguments
  }

函數

1.函數聲明

  • 示例
  function sum(x: number, y: number): number {
    return x + y;
  }
  • 輸入多余/少於要求的參數,是不被允許的
  sum(1, 2, 3) // 報錯
  sum(1) // 報錯

2.函數表達式

  • 示例
  let mySum: (x: number, y: number) => number = function (x, y) {
    return x + y
  }
  • =>用來表示函數的定義,左邊是輸入類型,需要用括號括起來,右邊是輸出類型

3.用接口定義函數的形狀

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

  let mySearch: SearchFunc = function(source, subString) {
    return source.search(subString) !== -1
  }

4.可選參數

  • 可選參數,必須接在必需參數后面
  • 可選參數,后面不允許再出現必須參數

5.參數默認值

  • 同ES6
  • 會將添加了默認值的參數,識別為可選參數
  • 不受"可選參數必須接在必需參數后面"的限制

6.剩余參數

  • 同ES6

7.重載

  • 允許一個函數接受不同數量或類型的參數時,作出不同的處理
  • 示例
  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('');
    }
  }
  • 如果多個函數定義有包含關系,需要優先把精確的定義寫在前面

進階

類型推斷

定義

  • 如果沒有明確指定類型,那么ts會依照類型推論規則推斷出一個類型

代碼示例

  let myFavoriteNumber = 'seven';
  myFavoriteNumber = 7; // 報錯,因為已推斷為字符串

強調

  • 如果定義的時候沒有賦值,會被推斷成any類型
  let myFavoriteNumber;
  myFavoriteNumber = 'seven';
  myFavoriteNumber = 7;

類型斷言

1.手動指定一個值的類型,然后才可以使用類型對應的方法,否則只能訪問公共屬性/方法

  function getLength(something: string | number): number {
    if ((<string>something).length) {
      return (<string>something).length;
    } else {
      return something.toString().length;
    }
  }

2.方法

  • <類型>值
  • 值 as 類型

3.斷言成一個聯合類型中不存在的類型是不允許的

  function toBoolean(something: string | number): boolean {
    return <boolean>something
  }

類型別名

定義

  • 用來給一個類型起個新名字

示例代碼

  type Name = string;
  type NameResolver = () => string;
  type NameOrResolver = Name | NameResolver;

字符串字面量類型

定義

  • 用來約束取值只能是某幾個字符串中的一個

示例代碼

  type EventNames = 'click' | 'scroll' | 'mousemove';
  function handleEvent(ele: Element, event: EventNames) {}

注意

  • 類型別名與字符串字面量類型都是使用type進行定義

元祖Tuple

定義

  • 數組合並了相同類型的對象,而元組合並了不同類型的對象

示例

  let tom: [string, number] = ['Tom', 25];

注意

1.當賦值或訪問一個已知索引的元素時,可以只賦值其中一項

  let tom: [string, number];
  tom[0] = 'Tom';

2.直接對元祖類型賦值時,需提供所有類型項

  let tom: [string, number];
  tom = ['Tom', 25];

3.當添加越界元素時,類型會被限制為定義項的類型

  let tom: [string, number];
  tom = ['Tom', 25];
  tom.push('male');
  tom.push(true); // 報錯

枚舉

定義

  • 用於取值被限定在一定范圍內的場景

簡單示例

  enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
  console.log(Days["Sun"] === 0); // true
  console.log(Days[0] === "Sun"); // true

手動賦值

  enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};

  console.log(Days["Sun"] === 7); // true
  console.log(Days["Mon"] === 1); // true
  console.log(Days["Sat"] === 6); // true

說明

  • 未手動賦值的枚舉項會接着上一個枚舉項遞增
  • 未手動賦值的枚舉項與手動賦值的重復了,ts不會察覺,后者只會覆蓋前者

枚舉項類型

1.常數項和計算所得項

2.計算所得項·示例

  enum Color { Red, Green, Blue = "blue".length };

3.如果緊接在計算所得項后面的是未手動賦值的項,那么它就會因為無法獲得初始值而報錯

  enum Color { Red = "red".length, Green, Blue }; // 報錯

常數枚舉

1.示例代碼

  const enum Directions {
    Up,
    Down,
    Left,
    Right
  }

  let directions = [ Directions.Up, Directions.Down, Directions.Left, Directions.Right ];

  var directions = [0, 1, 2, 3]; //編譯結果

2.常數枚舉與普通枚舉的區別是,它會在編譯階段被刪除,並且不能包含計算所得項

const enum Color {Red, Green, Blue = "blue".length};  // 報錯

外部枚舉

1.示例代碼

  declare enum Directions {
    Up,
    Down,
    Left,
    Right
  }

  let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

  var directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]; //編譯結果

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

3.外部枚舉與聲明語句一樣,常出現在聲明文件中

概言

  • TS除了實現了所有ES6中的類的功能以外,還添加了一些新的用法

修飾符

  public       	可被公開訪問
  private      	僅供自身訪問,子類也不可以訪問它的屬性/方法
  protected 	受保護的訪問,子類可以訪問它的屬性/方法

抽象類

  • 用abstract關鍵字定義(抽象類/抽象方法)
  • 不允許被實例化
  • 抽象方法必須被子類實現
  • 抽象類可以包含成員的實現細節

類與接口

類實現接口

  • 把各層級的類之間共有的特性提取出來進行實現的部分叫接口
  • 接口通過interface定義,通過implements實現
  • 一個類只能繼承一個類,但是可以實現多個接口
  • 接口不會幫你檢查類是否具有某些私有成員
  • 接口只會對類的實例部分進行類型檢查

接口繼承接口

  • 通過extends關鍵字來繼承

接口繼承類

  • 通過extends關鍵字來繼承
  • 在接口繼承類的時候,也只會繼承它的實例屬性和實例方法
  • 接口繼承了擁有私有或受保護成員的類時,這個接口只能被這個類或其子類所實現

泛型

定義

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

  • 示例代碼

  function createArray<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
      result[i] = value;
    }
    return result;
  }
  createArray<string>(3, 'x');      // ['x', 'x', 'x']

多個類型參數

  function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
  }
  swap([7, 'seven']);     // ['seven', 7]

泛型默認類型

  function createArray<T = string>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
      result[i] = value
    }
    return result;
  }

泛型約束

1.由於事先不知道它是哪種類型,所以不能隨意的操作它的屬性或方法

  function loggingIdentity<T>(arg: T): T {
    console.log(arg.length); // 報錯
    return arg;
  }

2.對泛型進行約束

  interface Lengthwise {
    length: number;
  }
  function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
  }

3.泛型之間也可以相互約束

function copyFields<T extends U, U>(target: T, source: U): T {
    for (let id in source) {
        target[id] = (<T>source)[id];
    }
    return target;
}

let x = { a: 1, b: 2, c: 3, d: 4 };

copyFields(x, { b: 10, d: 20 });

4.在泛型約束中使用類型參數

function getProperty<T, K extends keyof T> (obj: T, key: K ) {
  return obj[key]
}

let x = {a: 1, b: 2, c: 3, d: 4}

getProperty(x, 'a') // okay
getProperty(x, 'm') // error

泛型接口

  寫法一
  interface A {
    <T>(arg: T): T;
  }
  function fn<T>(arg: T): T {
    return arg;
  }
  let test: A = fn;
  test<number>(1);            // 手動指定-在調用時 傳遞 泛型參數類型
  test(1);                    // 類型推斷-在調用時 推斷 泛型參數類型

  寫法二
  interface A<T> {
    (arg: T): T;
  }
  function fn<T>(arg: T): T {
    return arg;
  }
  let test: A<number> = fn;   // 接口定義了需要傳遞類型參數T,這里為number
  test<number>(1)             // 報錯,因為類型定義A<number>已經指定
  test('1');                  // 報錯,必須符合接口A<number>參數類型

泛型類

  class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
  }

聲明文件

概要

1.使用第三方庫時,需要引用它的聲明文件,才能獲得對應的代碼補全、接口提示等功能

2.聲明語句中只能定義類型,切勿在聲明語句中定義具體的實現

3.示例代碼

  declare var jQuery: (selector: string) => any

4.注意

  • 帶有聲明語句的文件即為聲明文件
  • 聲明文件必需以 .d.ts為后綴
  • 如果ts無法解析聲明文件,檢查tsconfig.json中的files、include和exclude配置,確保其包含了對應庫的xx.d.ts文件

5.第三方聲明文件

  • 通常使用@types統一管理第三方庫的聲明文件
  • 示例
  npm install @types/jquery --save-dev

聲明合並

1.如果定義了兩個相同名字的函數、接口或類,那么它們會合並成一個類型

2.合並的屬性類型必須是唯一的

3.函數合並

  • 參考函數重載示例

4.接口合並

  interface Alarm {
    price: number;
  }

  interface Alarm {
    weight: number; 
  }

  // 等同於
  interface Alarm {
    price: number;
    weight: number;
  }

5.類合並

  • 與接口的合並規則一致

書寫聲明文件

1.聲明合並

  • 一個東西既可以是函數,也可以是對象(擁有子屬性)
  • 示例
  declare function jQuery(selector: string): any
  declare namespace jQuery {
    function ajax(url: string, settings?: any): void
  }

2.export

  • 聲明文件中禁止定義具體的實現
  • interface前是不需要declare的

3.export default

  • 只有 function、class 和interface可以直接默認導出,其他變量需先聲明,再默認導出
  • 一般會將導出語句放在整個聲明文件的最前面

4.commonjs規范下的export

  • commonjs導出
  module.exports = foo; 	// 整體導出
  exports.bar = bar; 		// 單個導出
  • 在導入方式上,有兩種跟es6語法相同
  • 官推導入方式(commonjs下)
  import foo = require('foo');   	// 整體導入
  import bar = foo.bar;			// 單個導入
  • 官推導出方式(commonjs下)(假如要為它寫類型聲明文件的話)
  export = foo
  declare function foo(): string
  • 兩種官推方式都是ts為了兼容AMD和commonjs規范而創立的

5.UMD庫的導出

  export as namespace '導出名'

6.在npm包/UMD庫中擴展全局變量

  declare global {
    interface String {
      prependHello(): string
    }
  }

7.模塊插件(declare module)

  // index.d.ts聲明
  import * as moment from 'moment';

  declare module 'moment' {
    export function foo(): moment.CalendarKey
  }

  // index.ts使用
  import * as moment from 'moment';
  import 'moment-plugin';

  moment.foo();

8.聲明文件中的依賴

  • 示例參考<模塊插件index.d.ts聲明>
  • 三斜杠指令
    • 早期版本中為了描述模塊之間的依賴關系而創造的語法
    • 使用場景:書寫一個全局變量,並且需要依賴一個全局變量聲明文件時
    • 示例
  /// <reference types="jquery" />

  declare function foo(options: JQuery.AjaxSettings): string
  • 三斜線指令必須放在文件的最頂端,它前面只允許出現單行或多行注釋
  • 拆分聲明文件
    • 示例
  /// <reference types="sizzle" />
  /// <reference path="JQueryStatic.d.ts" />
  /// <reference path="JQuery.d.ts" />
  /// <reference path="misc.d.ts" />
  /// <reference path="legacy.d.ts" />
	
  export = jQuery;
  • types用於聲明對另一個庫的依賴,path用於聲明對另一個文件的依賴

9.自動生成聲明文件

  • 命令行
    • 在命令行中添加--declaration(簡寫-d)
  • 配置文件
    • 在tsconfig.json中添加declaration選項
    • 示例代碼
  {
    "compilerOptions": {
      "module": "commonjs",
      "outDir": "lib",
      "declaration": true
    }
  }

發布聲明文件

1.將聲明文件和源碼放在一起(ts聲明查找也遵循a=>b=>c)

  • package.json中配置types或typings字段,指定聲明文件
  • 在項目根目錄下,放置一個index.d.ts聲明文件
  • 針對package.json的入口文件位置,放置一個聲明文件

2.將聲明文件發布到@types下

  • 與普通的npm模塊不同,@types統一由DefinitelyTyped管理

內置對象的聲明文件

  • TypeScript核心庫定義中,包含了所有游覽器環境用到的類型(ECMAScript,DOM和BOM標准)
  • TypeScript核心庫定義中,不包含Nodejs部分(需要npm install @types/node --save-dev)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM