TypeScript 筆記小結

typescript 總結筆記

前言介紹

  • typescript 的優勢
    靜態弱類型語言, 編譯時就會報錯, 下降bug,低級錯誤出現的可能性
    自帶代碼提示,類型註解
    對於多人合做的項目比較友好,下降溝通成本
  • 爲何學習 ts
    除了上面一些優勢以外, ts 能夠幫助咱們鍛鍊數據類型思惟(數據定義: 數據類型&結構), 提升咱們編碼的嚴謹性以及代碼的健壯性;
    本篇筆記就 ts 的理論基礎和實踐兩個方面進行了一些總結

理論基礎篇

經常使用類型

基礎篇就快速過一下...html

  • string
let s: string = 'i am string'
  • number
let n: number = 1
  • boolean
let b: boolean = true
  • null & undefined
// undefined 類型的變量只能被賦值爲 undefined
  // null 類型的變量只能被賦值爲 null
  // 賦值爲其餘類型會報錯
  let ud: undefined = undefined
  let nu: null = null
  • void 空值
// 沒有返回值的函數爲void
  // 聲明一個 void 類型的只能將它賦值爲 undefined 和 null
  const popup = (): void => {
    console.log('function no return')
  }
  let useless: void = undefined
  • any 任意類型, 實在沒招了就用這個吧
// 能夠被任何值賦值, 聲明未指定類型的變量也爲 any
  let anyType: any = 'str'
  • unkonwn
let uk: unknown;
  // unknown 和 any 的主要區別是 unknown 類型會更加嚴格:
  在對unknown類型的值執行大多數操做以前,咱們必須進行某種形式的檢查, 一般能夠用as斷言
  而在對 any 類型的值執行操做以前,咱們沒必要進行任何檢查。
  // 當 unknown 類型被肯定是某個類型以前,它不能被進行任何操做好比實例化
  • 數組array
let arr1: (number | string)[] = [1, 2, 3, '2121']
  let arr2: Array<number | boolean> = [2, 2, 2, true]
  • 元組
// 表示一個已知元素數量和類型的數組,各元素的類型沒必要相同;越界不能訪問
  // 在函數的剩餘參數中定義參數的個數和類型
  let t1: [string, number, boolean | string]
  t1 = ['hello', 123, false]
  • never
// 永不存在的值的類型
  // never類型: 老是會拋出異常或不會有返回值的函數表達式或箭頭函數表達式的返回值類型
  // 不能賦值給除了 never 類型的其餘類型, 不能接受其餘類型
  const err = (msg: string): never => {
    throw new Error(msg)
  }
  // err('hahaahah')
  • symbol
let ss: symbol = Symbol('hello')
  console.log(ss)
  • object 代表數據類型是 object
let obj: {name: string, value: number} = { name: 'huhua', value: 1232 }
  let obj1: object = { name: '哈哈', value: 1232 }
  console.log(obj, obj1, obj.name)
  // console.log(obj1.name) // name 不在 object 上
  • function 具體後面細講
let myAdd = (x: number, y: number): number => x + y
  let add = (x: number, y: number) => x + y // 類型推斷, 沒必要註明返回值類型
  console.log(myAdd(1, 2), add(3, 100))

  let compute: (x:number, y:number) => number   // 定義函數類型
  compute = (aaa, bbb) => aaa + bbb

枚舉類型 enum

枚舉: 咱們能夠理解爲一組常量的集合, 能夠幫助咱們解決一些硬編碼問題
特別是 if 語句中的判斷值vue

  • 數字枚舉
export enum EState {
  one = 1,
  two,
  three,
  four,
  five,
  six,
  seven
}
能夠正反取值: EState['one'] === 1; EState[1] === 'one'
方便維護一個狀態數組; 另外在組件中能夠賦值給一個變量
  • 字符串枚舉
enum Direction {
  Up = 'Up',
  Down = 'Down',
  Left = 'Left',
  Right = 'Right'
}

console.log(Direction['Right'], Direction.Up); // Right Up
  • 異構枚舉(混合)
enum StrNum {
  n = 0,
  y = 'yes'
}
  • 常量枚舉(const 聲明)
// 只須要對象的值時可使用常量枚舉, 提升性能
const enum Direction {
  Up = 'Up',
  Down = 'Down',
  Left = 'Left',
  Right = 'Right'
}

const up = Direction.Up
console.log(up)

接口 interface

接口(Interfaces)用於對「對象的形狀(Shape)」進行描述
接口一般用來約束咱們定義的對象, 函數, 類的結構和類型react

  • 對象約束
// 賦值的時候,變量的形狀必須和接口的形狀保持一致(不能多也不能少,類型還必須一致)
interface Person {
  readonly id: number // 只讀屬性
  name: string
  age: number
  sex?: string // 可選屬性
  [key: string]: any //  索引類型, 值爲任意屬性; 以上必須爲 any 的子級
}
  • 函數約束
只是約束函數的形狀, 沒有實質性的聲明和計算
interface Func {
  (x: number, y: number): number
}
let addSum1: Func
addSum1 = (a, b) => a + b
  • 類約束
// 不一樣類之間公有的屬性或方法,能夠抽象成一個接口, 來被類實現(implements)
// 類必須實現接口中聲明的全部屬性;能夠定義接口未聲明的屬性
// 接口只能約束類的公有成員 public
// 接口不能約束類的構造函數
interface Man {
    name: string
    age: number
}

class Huhua implements Man {
    // 類中聲明共有屬性
    name!: string // 賦值斷言
    age!: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    eat() {
        console.log('eat food')
    }
}
  • 接口繼承
// 接口繼承接口
interface Alarm {
    alert();
}
interface LightableAlarm extends Alarm {
    lightOn();
    lightOff();
}
// 接口繼承類
class Point {
    x: number;
    y: number;
}
interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};

函數類型

  • 函數類型定義:
// function 聲明
function add(a:number, b: number) {
  return a + b
}
// 類型結構聲明, 表達式另外聲明
let add: (a: number, b: number) => number
type Add: (a: number, b: number) => number
interface IAdd {
  (a: number, b: number): number
}
  • 參數
// 可選參數, 默認參數, 剩餘參數: 注意順序
function add(a: number, b = 100, c?: number) {
  return c ? a + b + c : a + b
}
function add(x: number, ...rest: number[]) {
  return x + rest.reduce((pre, acc) => pre + acc)
}
  • 函數重載
同名函數多類型兼容, 根據參數的不一樣來實現不一樣功能, 進行匹配
function add(...rest: number[]): number
function add(...rest: string[]): string
function add(...rest: any[]): any {
  let first = rest[0]
  if (typeof first === 'string') {
    return rest.join('')
  }
  if (typeof first === 'number') {
    return rest.reduce((pre, acc) => pre + acc)
  }
}

類的類型 class

ts主要添加成員的類型註解和成員修飾符;
ES6中類的數據類型就是函數,類自己就指向構造函數, 其方法都定義在構造函數的 prototype 屬性上.咱們能夠經過 ClassName.prototype.xxx 去訪問git

  • 類聲明
class Car {
  // 實例屬性: 這樣聲明要有初始值
  _wheel: number = 4
  // 實例屬性成員構造器: 默認返回實例對象(即this)
  constructor(name: string) {
    this.name = name
  }
  // 只讀屬性
  readonly oil: string = '汽油'
  // public 默認的: 成員是能夠被外部訪問
  public name: string = 'car'
  // 實例方法
  run() { console.log(this.name + 'runing...') }
  // 私有成員: 成員是隻能夠被類的內部訪問
  private priv() { console.log('priv') }
  // 被保護成員: 成員是隻能夠被類的內部以及類的子類訪問
  protected pro() {}
  // 靜態成員: 能夠被類名調用和其子類名調用
  static seats: string = '座位'
}
let bz = new Car('benz') // 經過 new 來實例化
let bm: Car = new Car('bm') // 類的類型
console.log(Car.seats)
  • 類繼承
class Bmw extends Car {
  constructor(name: stirng, public color: string) {
    // 先調用父類的實例
    super(name)
    this.color = color
  }
}
console.log(Bmw.seats)
  • 抽象類 abstract

抽象類沒法實例化, 通常做爲基類使用, 咱們能夠抽離其餘類的公共屬性和方法
寫入抽象類中github

abstract class Animal {
  // abstract 關鍵字是用於定義抽象類和在抽象類內部定義抽象方法
  abstract say(): void;
  move(): void {
    console.log('i can move')
  }
}

class Dog extends Animal {
  // 聲明抽象類中的方法, 這裏子類能夠對父類方法進行重寫; 實現所謂的多態
  say() {
    console.log('汪汪汪');
  }
}

let dog1 = new Dog()
dog1.say() // 汪汪汪
dog1.move() // i can move
  • 類實現接口
不一樣類之間能夠有一些共有的特性,這時候就能夠把特性提取成接口(interfaces),用 implements 關鍵字來實現
// 類必須實現接口中聲明的全部屬性(至關於約束公有屬性);能夠定義接口未聲明的屬性
// 接口只能約束類的公有成員 public
// 接口不能約束類的構造函數
interface Alarm {
    alert();
}

interface Light {
    lightOn();
    lightOff();
}

class Car implements Alarm, Light {
    alert() {
        console.log('Car alert');
    }
    lightOn() {
        console.log('Car light on');
    }
    lightOff() {
        console.log('Car light off');
    }
}

泛型(至關於給類型傳參)

泛型:在定義函數、接口或類的時候,不預先指定具體的類型,而在使用的時候再指定類型的一種特性。
在聲明的同時指定類型變量的類型值vuex

// 1.函數約束
// 類型T不須要預先指定 至關於any類型
// 保證輸入類型和返回值類型是一致的 彌補了any類型的缺點
function log<T>(v: T): T {
  return v;
}
let s: string = "generics";
let a = log(s);
console.log(a);
console.log(log(1111));

// 2.函數類型約束
// 聯合類型,類型別名與字符串字面量類型都是使用 type 進行定義。
// type Log = <T>(v: T) => T // 類型別名
interface Log {
  <T>(v: T): T;
}
let myLog: Log = log;
console.log(myLog([1, 2, 3]));

// 3.泛型接口
// 接口的全部屬性均可以受到泛型變量的約束
// 能夠傳入默認類型
interface IGeneric<T = string> {
  (v: T): T;
}
let IG1: IGeneric<number> = log;
console.log(IG1(123));

// 4.泛型類
class GenericNumber<T> {
  // 泛型變量不能約束類的靜態屬性
  // zeroValue: T = T;
  add(x: T, y?: T) {
    console.log(x);
    return x;
  }
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.add(1);
let myG1 = new GenericNumber();
myG1.add("hello ts generics");

// 5.泛型約束
interface Length {
  length: number;
}

// T繼承Length接口, 這樣的話輸入的參數必須具備length屬性 獲取value.length就是合法的了
function ggg<T extends Length>(value: T): T {
  console.log(value, value.length);
  return value;
}
ggg('hello')
ggg([1, 2, 3])

理論進階篇

ts類型檢查機制

  • 類型推斷

根據tsconfig.json的配置規則進行推斷, 上下文推斷, 類型斷言as, 雙斷言,
is關鍵字: xx is string, 賦值斷言 let x!: stringtypescript

  • 類型兼容

不一樣變量相互賦值時的類型檢查
函數兼容: 參數個數, 參數類型, 返回值類型
接口兼容: 成員少能夠被賦值爲成員多的json

  • 類型保護

在特殊區塊使用肯定的類型屬性和方法segmentfault

1.instanceof
if (c instanceof A) c.a 
2.in
if (c in C) c.a
3.typeof
函數的參數爲聯合類型
if (typeof arg === 'string') {} else {}
4.聲明類型保護方法
字面量

聯合,交叉,索引類型

  • 交叉 & 合併類型屬性
  • 聯合 | 指定類型的全部可能性
  • 索引
// 縮小類型的約束範圍;
// 索引類型查詢操做符K keyof T: 聯合類型的集合;
// 索引類型訪問操做符 T[K]; 
// 泛型約束 T extends U
interface IObj {
  a: string
  b: number
}
let key: keyof IObj
let k: IObj['a']

let iobj = {
  a: 1,
  b: 2,
  c: 'ccc'
}
// 泛型索引約束
function getObjValue<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
  return keys.map(key => obj[key])
}
console.log(getObjValue(iobj, ['a', 'c']));
// console.log(getObjValue(iobj, ['a', 'd'])); 保錯

工程實踐篇

這裏是針對咱們在正式開發中使用 ts 的一些技巧及規範說明數組

tsconfig.json

// ts項目配置文件說明
https://segmentfault.com/a/11...
http://www.typescriptlang.org...

聲明文件 xxx.d.ts

declare var 聲明全局變量
declare function 聲明全局方法
declare class 聲明全局類
declare enum 聲明全局枚舉類型
declare namespace 聲明(含有子屬性的)全局對象
declare interface 和 type 聲明全局類型
export 導出變量
export namespace 導出(含有子屬性的)對象
export default ES6 默認導出
export = commonjs 導出模塊, import xx = require('xxx')
export as namespace UMD 庫聲明全局變量
declare global 擴展全局變量
declare module 擴展模塊

ts工具類(泛型)

  • Partial: 將屬性所有變爲可選.
type Partial<T> = { [P in keyof T]?: T[P] };
type p = Partial<InterfaceXXX>
  • Required: 將可選變爲必選
  • Exclude: 從 T 中排除出可分配給 U的元素
type T = Exclude<1 | 2, 1 | 3> // -> 2
  • Omit: Omit<T, K>的做用是忽略T中的某些屬性.
type Foo = Omit<{name: string, age: number}, 'name'> // -> { age: number }
  • Merge: Merge<O1, O2>的做用是將兩個對象的屬性合併:
  • Intersection<T, U>的做用是取T的屬性,此屬性一樣也存在於U.
  • Overwrite<T, U> U的屬性覆蓋 T中相同的屬性

開發的一些技巧

待更新...

vue 項目中使用的一些問題

本人是在 vue 項目中首先使用的, 發現支持並非很好...可是仍是咬牙寫完了一個項目, 後續打算在 react使用一下

  • 相關插件文檔
    vue-class-component:

    https://github.com/vuejs/vue-docs-zh-cn/tree/master/vue-class-component

    vue-property-decorator:

    https://github.com/kaorun343/vue-property-decorator

    vuex-class:

    https://github.com/ktsn/vuex-class

    vuex-module-decorators

    https://github.com/championswimmer/vuex-module-decorators
  • 類型斷言: 用於繞過ts編譯器的類型檢查; 即手動指定一個值的類型
<類型>值 =>  <string> value
      值 as 類型 => value as string
    (this.$refs['multiTable'] as any).clearSelection()
    (this.$refs['downParams'] as Form).resetFields()
  • $refs 雙重斷言
((this.$refs.saveTagInput as Vue)['$refs'].input as HTMLInputElement).focus()
  • 使用三方庫時安裝或者本身寫聲明文件
    @types/xxx

未完待續, 後續在更新...

相關文章
相關標籤/搜索