typescript使用及介紹

typescript

官網

介紹

TypeScript 是 JavaScript 的一個超集,主要提供了類型系統和對 ES6+ 的支持,它由 Microsoft 開發,代碼開源於 GitHub 上。

特點

  • 可以在開發階段和編譯階段就發現大部分錯誤,這總比在運行時候出錯好

  • 不顯式的定義類型,也能夠自動做出類型推論

  • 即使 TypeScript 編譯報錯,也可以生成 JavaScript 文件

  • Google 開發的 Angular 就是使用 TypeScript 編寫的

  • TypeScript 擁抱了 ES6+ 規範

痛點

有一定的學習成本,需要理解接口(Interfaces)、泛型(Generics)、類(Classes)、枚舉類型(Enums)等前端工程師可能不是很熟悉的東西短期可能會增加一些開發成本,多寫一些類型的定義,長期維護的項目,TypeScript 能夠減少其維護成本

安裝

npm install -g typescript
tsc -v 測試

編譯

tsc hello.ts

類型不匹配時,編輯報錯,但可以生成js(編輯通過),如果不希望編譯通過需要配tsconfig.json

 

類型

原始類型

布爾值、數值、字符串、null、undefined、Symbol

void、any、never、聯合、函數、數組類型、類 ....

內置對象類型

DOM

Document、HTMLElement、Event、NodeList ...

工具類型

Boolean、Error、Date、RegExp、Math ...

類型註解

聲明 變量:類型;           // undefined   || false
聲明 變量:類型=值;        //嚴格要求值是定義的類型
​
類型權重
    any > boolean number string void 聯合、函數、數組類型、類 > null undefined -> never
權重高的類型,接受低權重的類型值,反之亦然

ts變量作用域

全局作用域(項目) 默認

在一個項目目錄下,所有文件的變量都暴露在全局

模塊作用域(文件)

變量封閉在模塊內部,在內部全局使用

空類型(void)

function alertName(): void{}  //一個函數不允許返回任何值

任意類型(any)

any 允許被賦值爲任意類型,任何操作都返回任意類型

類型推論

沒有明確的指定類型,依照值推斷出一個類型。

聯合類型

取值可以爲多種類型中的一種,沒列出的不可以

let myFavoriteNumber: string | number;

對象類型

依賴接口來描述,或者class描述

interface Person {
  name:string; //必續
  readonly age:number; //只讀
  address?:string;  //可選
  // [key:key類型]:值類型      定義對象任意屬性
  [propName:string]:any //必填屬性和可選屬性,都要是任意屬性的子屬性(子數據類型)
}
​
p2={
  name: '劉鐵柱',
  age: 16,
  city: '西安'
}

數組類型

// 變量:類型[] 
// 變量:Array<類型> 
// let 變量:(類型名|類型名2)[]
​
let arr:number[]=[1,2,3,4]
let arr2:(number|string)[]=['aa',12]
let arr4:Array<number>=[12,3]

函數類型

對一個函數有輸入和輸出,進行約束

//聲明式
//function 函數名(參數:類型):返回類型{}
function sum(x: number, y: number): number {}
​
//函數表達式
//let 變量:輸入類 => 輸出類型 = function(參數){}
let show3:(a:number,b:string,c?) => number = function (a,b){
  return a;
}
​
//接口定義函數類型
interface Func {
  (a:number,b:string):boolean
}
let show5:Func = function(a,b){return false}
​

可選參數在後

類型斷言

繞過編譯器的類型推斷,手動指定一個值的類型

//<類型>變量 
//變量 as 類型  
//類型斷言不做類型轉換 
//自定義類型也可以用來做斷言
//權重最低
​
(<string>a).length   //斷言字符
(a as string).length

類型聲明文件

ts 使用第三方庫時,我們需要引用它的聲明文件,declare 關鍵字來定義它的類型,幫助 TypeScript 判斷我們傳入的參數類型對不對,聲明文件xx.d.ts

declare let $:(any)=>any; //定義
​
//引入文件  三斜線指令
/// <reference path="./jQuery.d.ts" />

安裝第三方的庫,選擇安裝類型聲明文件,庫具備了類型

npm i jquery -S
npm i @types/jquery
​
import * as $ from 'jquery'
$ 具備類型的
​
//注意 現在絕大部分的庫都具備了類型聲明文件,而無需單獨安裝

內置對象類型

Boolean、Error、Date、RegExp,Math ...

Document、HTMLElement、Event、NodeList ..

let b2:Boolean = new Boolean();//對類型內置
let oDiv:HTMLDivElement = document.createElement('div');
​
//重寫 內置對象類型
interface Math {
  pow(x:number,y:string):number|string
}
​
Math.pow(12,'qq')
​

定義了一件事物的抽象特點,包含它的屬性和方法,對象是類的實例,通過 new 生成,OOP特性封裝、繼承、多態,類成員(實例屬性,方法,靜態屬性、方法)

訪問控制符

控制類內部的屬性(實例,類)|方法(實例,類) 的被訪問權限

//public   公共的 誰(父子)都可以訪問(類內外)
//protected  當前類內使用 + 子類類內
//private  當前類內使用
​
class Person {
​
  public namee:string='alex';//實例屬性
  private age:number; //沒有默認值的實例屬性
  protected address:string; //沒有默認值的實例屬性
  address2:string; //不加的情況下 是public
​
  protected static VER:string='1.11.1' //類屬性 靜態屬性
    
    constructor(public namee:string,public age:number){
    this.namee = namee;//實例屬性第一次的修改
    this.age = age||0;//實例屬性第一次的修改
    this.address
  }
​
  private show(){}
  private static show2(){}
}

接口

用於對象的形狀描述,函數的類型、輸入出返回值的描述,對類的行爲進行抽象

實現接口

不同類之間可以有一些共有的特性,這時候就可以把特性提取成接口(interfaces),用 implements 關鍵字來實現,對象函數類都可以實現接口

class Person implements Action1{
  ...
}
  
class Person implements Action1,Action2{
  ...
}

泛型

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

函數泛型

//定義 function 函數<T>(length: number, value: T): Array<T> {}
​
//調用 函數<string>(參數) //使用的時候再指定類型
​
//栗子
function swap<T,U>(tuple:[T,U]):[U,T]{
  return [tuple[1],tuple[0]]
}
​
let result = swap([7,'seven'])// reuslt = ['seven',7]

接口泛型

interface SearchFunc {
  <T>(source:string,subString:T):Array<T>
}
​
  //約定函數
let mySearch:SearchFunc = function<T>(source,subString){
  return [subString]
}
​
mySearch<object>('qq',{a:1,b:2})
  
//約定一個類
interface SearchClass<T>{
  title?:string
  eat(source:string,subString:T):Array<T>
}
​
class Person3 implements SearchClass<boolean>{
  title?: string = 'bmw'
  eat(source: string, subString: boolean): boolean[] {
    //業務邏輯
    return [true]
  }
}
​

類泛型

class Person<T,U>{
  msg:Array<T>;
  msg2:[T,U]

  constructor(msg:Array<T>){

  }
  show<A,V>(arr:[V,A]):void{
    //..
  }
}

new Person<string,number>(['bmw'])
new Person<boolean,number>([false])

 

裝飾器

  • 是一種特殊類型的聲明,它能夠被附加到類聲明,方法, 訪問符,屬性或參數上去裝飾他們

  • 裝飾器使用 @expression這種形式

  • expression求值後必須爲一個函數

  • 它會在運行時被調用,被裝飾的聲明信息做爲參數傳入

定義

// vuex-class.ts
function State(type:any):any{
  return function(){
    console.log('裝飾器業務')
  }
}
function Mutation(type:string):any{
  return function(){
    console.log('裝飾器業務')
  }
}
function Component(target:any){
  // do something with "target" ...
  console.log('裝飾器',target)
}

export {State,Mutation,Component}

使用

import {Component,Mutations,State} from 'vuex-class'

//裝飾類
@Component
class App {}

Component(
  class App2{}
)

//裝飾類成員- 方法
@Component
class App{
  @Mutations('ADD_ITEM') ADD_ITEM:string // this.ADD_ITEM(信息)
}

//裝飾類成員- 屬性
@Component
class App{
  @State('bNav') stateNav:string // {{this.stateNav}}
}

元組(Tuple)

表示一個已知元素數量和類型的數組

let x: [string,number];
x = ['hello',10]
x[1]//10

let [a,b,c] = x; // a = hello b = 10   c= undefined

 

枚舉(enum)

爲一組數值賦予友好的名字

enum Color {Red,Green,Blue,Yellow};//數據位 打0開始
let c: Color = Color.Blue // ouput 2  返回的是數據位
let ColorName:string = Color[2] // 'Blue'
let ColorName2:string = Color[c] // 'Blue'

never

永不存在的值的類型,是任何類型的子類型(包括undefined|null)

let a:never;//never
let a2: never = a; // never只接受never類型的值
let a3: never = 10; //不能有其他值

function show (arg:number):never{
  //返回never的函數必須存在無法達到的終點
  // return arg;
  // return undefined
  // return undefined

  // while(true){}
  throw Error('....')

}

object

非原始類型

function createElement (o:object|null):object{
  return o;
}

let o1 = createElement({prop:'title'}) // ok
let o2 = createElement(null)
// createElement()


export {}

類型別名(type)

  • 類型別名會給一個類型起個新名字

  • 類型別名有時和接口很像,不可以extends和 implements

  • 但是可以作用於原始值,聯合類型,元組以及其它任何你需要手寫的類型

  • 不會新建一個類型

接口(intervace) vs 別名(type)

  inteface type
約定對象類型
約定函數類型
同名合併 ×
基礎類型、聯合類型、元組、自定義類型 ×

公共的用 interface 實現,不能用 interface 實現的再用 type 實現。

栗子

type Name = string;//類型別名
type NameResolver = ()=>string;//函數類型,返回字符

function getName(n:NameResolver):Name{
  if(typeof n === 'string'){
    return n;
  }else{
    return n()
  }
}

type Container<T> = {a:number,value:T,b:string} //別名 也可以含有泛型

class App {
  o:Container<boolean>={a:12,value:false,b:'bmw'}
}

交叉類型

類型保護

字面量類型

映射類型

索引類型

TIPS

keyof

interface iPeople {
  name: string;
  age: number
}
 
type T = keyof iPeople // -> "name" | "age"

in

type Keys = "a" | "b"
type Obj =  {
  [p in Keys]: any
} // -> { a: any, b: any }

typeof

一般我們都是先定義類型,再去賦值使用,但是使用 typeof 我們可以把使用順序倒過來

const options = {
  a: 1
}
type Options = typeof options

條件類型

條件類型可以根據其他類型的特性做出類型的判斷

T extends U ? X : Y

舉例

interface Id { id: number, /* other fields */ }
interface Name { name: string, /* other fields */ }
declare function createLabel(id: number): Id;
declare function createLabel(name: string): Name;
declare function createLabel(name: string | number): Id | Name;

使用條件類型

type IdOrName<T extends number | string> = T extends number ? Id : Name;
declare function createLabel<T extends number | string>(idOrName: T): T extends number ? Id : Name;

 

工具泛型

Partial

作用是將傳入的屬性變爲可選項.

interface iPeople {
    title: string;
    name: string;
}
 
const people: Partial<Todo> = {
    title: 'Delete inactive users',
};
//定義的結構可以是接口iPeople的任意key

Readonly

Readonly 作用是將傳入的屬性變爲變成只讀

interface iPeople {
    title: string;
    name: string;
}
 
const people: Readonly<Todo> = {
    title: 'todo list',
    name: chenfeng;
};
//title name屬性就是隻讀的了

Required

Required 的作用是將傳入的屬性變爲必選項

interface iPeople {
    title?: string;
    name?: string;
}
 
const people: Required<iPeople> = { title: 'ts' }; // Error: property 'name' missing

Exclude<T,U>

T 中排除那些可以賦值給 U 的類型。

Exclude 實現源碼 node_modules/typescript/lib/lib.es5.d.ts

type Exclude<T, U> = T extends U ? never : T;

實例:

type T = Exclude<1|2|3|4|5, 3|4>  // T = 1|2|5 

此時 T 類型的值只可以爲 125 ,當使用其他值是 TS 會進行錯誤提示。

Error:(8, 5) TS2322: Type '3' is not assignable to type '1 | 2 | 5'.

Extract<T,U>

T 中提取那些可以賦值給 U 的類型。

Extract實現源碼 node_modules/typescript/lib/lib.es5.d.ts

type Extract<T, U> = T extends U ? T : never;

實例:

type T = Extract<1|2|3|4|5, 3|4>  // T = 3|4

此時T類型的值只可以爲 34 ,當使用其他值時 TS 會進行錯誤提示:

Error:(8, 5) TS2322: Type '5' is not assignable to type '3 | 4'.

Pick<T,K>

T 中取出一系列 K 的屬性。

Pick 實現源碼 node_modules/typescript/lib/lib.es5.d.ts

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

實例:

假如我們現在有一個類型其擁有 nameagesex 屬性,當我們想生成一個新的類型只支持 nameage 時可以像下面這樣:

interface Person {
  name: string,
  age: number,
  sex: string,
}
let person: Pick<Person, 'name' | 'age'> = {
  name: '小王',
  age: 21,
}

Record<string,any>

Record<string,any> 用這個來聲明對象結構的類型

//用於定義一個javascript的對象,key是字符串,value是任意類型
const people:Record<string,any> = {
    name: 'chengfeng',
    age: 10
}

declare

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章