TypeScript入門學習記錄

前言:TypeScript是Js的一個超集,而且支持ES6,是一種面向對象的編程方法,經常使用的用法主要包括如下幾個部分:基礎類型,類型批註,類型推斷,接口,枚舉,修飾符,泛型,命名空間,類,元組等。node

TypeScript安裝

使用npm安裝面試

npm config set registry https://registry.npm.taobao.org
複製代碼

安裝TypeScripttypescript

npm install -g typescript
複製代碼

而後就能夠用tsc命令來編譯ts文件npm

tsc -v #查看ts版本號
tsc app.ts #編譯指定ts文件
複製代碼

編譯完成後會在該文件的相同目錄下生成app.js文件,而後使用node app.js便可運行該文件編程

或者安裝ts-node插件,而後能夠直接使用命令ts-node運行ts文件json

ts-node app.ts
複製代碼

TypeScript變量聲明

在ts中,變量聲明的時候同時須要聲明變量的類型數組

  • 變量類型:
const count :number=111
const myName:String="aaa"
複製代碼
  • 對象類型:
const myObj:{
    name:string,
    age:number
}={
    name:"張三",
    age:18
}
複製代碼
  • 數組類型:
const names:string[]=["aaa","bbb","ccc"]
複製代碼
  • 類類型:
class Person{}
const zhangsan:Person=new Person()
複製代碼
  • 函數類型:
const seeZhangSan:()=>string=()=>{return "lisi"}
複製代碼
  • 聯合類型
var val:string|number 
val = 12 
console.log("數字爲 "+ val) //數字爲 12
val = "Hello" 
console.log("字符串爲 " + val) //字符串爲 Hello
//若是賦值其餘類型就會報錯
var val:string|number 
val = true //報錯
複製代碼

也能夠將聯合類型做爲函數參數使用安全

function disp(name:string|string[]) { 
        if(typeof name == "string") { 
                console.log(name) 
        } else { 
                var i; 
                for(i = 0;i<name.length;i++) { 
                console.log(name[i])
                } 
        } 
} 
disp("Runoob") 
console.log("輸出數組....") 
disp(["Runoob","Google","Taobao","Facebook"])
複製代碼

聯合類型數組markdown

var arr:number[]|string[]; 
var i:number; 
arr = [1,2,4] 
console.log("**數字數組**")  
 
for(i = 0;i<arr.length;i++) { 
   console.log(arr[i]) 
}  
 
arr = ["Runoob","Google","Taobao"] 
console.log("**字符串數組**")  
 
for(i = 0;i<arr.length;i++) { 
   console.log(arr[i]) 
}
複製代碼

函數

參數類型與返回值類型

在ts中,函數能夠指定參數類型與返回值類型app

//函數參數類型註解
function getTotal1(one:number,two:number){
    return one+two
}
let total1=getTotal1(1,2)
//函數返回值類型註解
function getTotal2(one:number,two:number):number{
    return one+two
}
let total2=getTotal2(1,2)

//函數參數是對象時的註解方式
function add({one,two}:{one:number,two:number}){
    return one+two
}

let total3=add({one:1,two:2})
function getNumber({one}:{one:number}){
    return one
}
let one=getNumber({one:1})
複製代碼

可選參數與默認參數

  • 可選參數

在ts函數中,可使用?定義可選參數

function buildName(firstName: string, lastName?: string) {
    if (lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}
 
let result1 = buildName("Bob");  // 正確
let result2 = buildName("Bob", "Adams", "Sr.");  // 錯誤,參數太多了
let result3 = buildName("Bob", "Adams");  // 正確
複製代碼
  • 默認參數

能夠指定參數的默認傳入值,若是調用該函數時未傳入參數則使用該默認值

function calculate_discount(price:number,rate:number = 0.50) { 
    var discount = price * rate; 
    console.log("計算結果: ",discount); 
} 
calculate_discount(1000) 
calculate_discount(1000,0.30)
複製代碼
  • 剩餘參數

當咱們不知道要向函數傳入多少個參數,這個時候咱們就可使用剩餘參數來定義,剩餘參數容許咱們將一個不缺性數量的參數做爲數組傳入

function addNumbers(...nums:number[]) {  
    var i;   
    var sum:number = 0; 
    for(i = 0;i<nums.length;i++) { 
       sum = sum + nums[i]; 
    } 
    console.log("和爲:",sum) 
 } 
 addNumbers(1,2,3) 
 addNumbers(10,10,10,10,10)
複製代碼

數組

  • 數組解構
var arr:number[] = [12,13] 
var[x,y] = arr // 將數組的兩個元素賦值給變量 x 和 y
console.log(x) //12
console.log(y) //13
複製代碼
  • 數組做爲參數傳遞給函數
var sites:string[] = new Array("Google","Runoob","Taobao","Facebook") 
 
function disp(arr_sites:string[]) {
        for(var i = 0;i<arr_sites.length;i++) { 
                console.log(arr_sites[i]) 
        }  
}  
disp(sites);
複製代碼
  • 做爲函數的返回值
function disp():string[] { 
        return new Array("Google", "Runoob", "Taobao", "Facebook");
} 
 
var sites:string[] = disp() 
for(var i in sites) { 
        console.log(sites[i]) 
}
複製代碼

枚舉類型enum

  1. 基礎用法:
enum Color {Red, Green, Blue}
let c: Color = Color.Red;
let d: Color = Color.Green;
let e: Color = Color.Blue;
console.log('enum',c,d,e) //0,1,2
複製代碼

2.手動設置初始值 第一位未設置的默認0,後面遞增.遇到有初始值的,後面的按照初始值+1.

enum Color {Red, Green=2, Blue}
let c: Color = Color.Red;
let d: Color = Color.Green;
let e: Color = Color.Blue;
console.log('enum',c,d,e) //0,2,3
複製代碼
enum Color {Red, Green=2, Blue,Yellow=7 ,Dark}
let c: Color = Color.Red;
let d: Color = Color.Green;
let e: Color = Color.Blue;
let f: Color = Color.Yellow;
let g: Color = Color.Dark;
console.log('enum',c,d,e,f,g) //0 2 3 7 8
複製代碼

3.屬性獲取

在賦予初始值的時候是以鍵值對的形式給的,那怎麼拿到'鍵'呢?

enum Color {Red, Green=2, Blue,Yellow=7 ,Dark}
let c1: string = Color[0];
let c: Color = Color.Red;
let d1: string = Color[1];
let d: Color = Color.Green;
let e1: string = Color[2];
let e: Color = Color.Blue;
let f1: string = Color[3];
let f: Color = Color.Yellow;
let g1: string = Color[4];
let g: Color = Color.Dark;
console.log('enum',c1,c,d1,d,e1,e,f1,f,g1,g) 
//Red 0 undefined 2 Green 3 Blue 7 undefined 8
複製代碼

這裏會出現undefined的緣由是由於[0]這裏面的0表明的是鍵所對應的值,由於沒有一個鍵是1或者4(鍵值只存在0 2 3 7 8),因此1和4鍵對應的值是undefined 4. 設置初始值爲字符串 假如設置的字符串不是最後一位,那後面的屬性將沒法設置默認值.咱們以前說過要遞增+1,若是前一個是字符串,ts將沒法處理初始化.

enum Color {Red, Green=2, Blue,Yellow='b' ,Dark='b'}
let g: Color = Color.Dark;
let test: string = Color['b'];
console.log('enum',g,test) //b undefined
複製代碼

同時咱們,發現,並不能用字符串值拿到鍵位值,那麼怎麼拿到呢?通過查詢資料得知,字符串賦值以後不進行反向映射.故拿不到對應鍵位值.

總結一下:

  1. 枚舉成員能夠是純數值,純字符串,數值字符串混合,三種狀況.不能使用計算值,
  2. 涉及字符串混合的限制條件比較多,因此儘可能避免字符串的混合.
  3. 添加的索引爲賦予的值,沒有就是默認值.
  4. 字符串並無添加索引,因此沒法根據值得到鍵.

TypeScript 接口 interface

接口是一系列抽象方法的聲明,是一些方法特徵的集合,這些方法都應該是抽象的,須要由具體的類去實現,而後第三方就能夠經過這組抽象方法類調用。interface本質就是一個類的說明書,是約束條件

interface People {
  name: string;
  age: number;
  height: number;
  //?表示該屬性可存在可不存在
  weight?: number;
  //能夠添加任意屬性,該屬性名稱爲字符串類型,同時該屬性的內容爲任意
  [propname: string]: any;
  //函數返回類型爲string
  say(): string;
}
複製代碼

相似的一個用法type

//type alias類型別名
type Lady={name:string,age:number}
const people2:Lady[]=[
    {name:'zhangsan',age:11},
    {name:'lisi',age:22},
]
class Madam{
    name:string;
    age:number
}
const people3:Madam[]=[ 
    {name:'zhangsan',age:11},
    {name:'lisi',age:22},
]
複製代碼

這裏存在一個和接口相似的定義type

interface和type的異同

  • interface可以聲明合併,type不行
interface User {
  name: string
  age: number
}
interface User {
  sex: string
}
/* User 接口爲 { name: string age: number sex: string } */
複製代碼
  • type能夠聲明基本類型別名,聯合類型,元組等類型,interface不行
// 基本類型別名
type Name = string
// 聯合類型
interface Dog {
    wong();
}
interface Cat {
    miao();
}
type Pet = Dog | Cat
// 具體定義數組每一個位置的類型
type PetList = [Dog, Pet]
複製代碼

接口繼承及使用

//接口繼承
interface NewPeople extends People {
  done(): string;
}

const boy = {
  name: "zhansan",
  age: 18,
  height: 160,
  weight: 100,
  sex: "女",
  phone: 111111111,
  say() {
    return "i am zhangsan";
  },
  done() {
    return "i can done";
  },
};

const screenResume = (boy: People) => {
  boy.age < 24 && boy.height > 170 && console.log(boy.name + "進入面試");
  boy.age >= 24 || (boy.height < 170 && console.log(boy.name + "已被淘汰"));
};

const getResum = (boy: NewPeople) => {
  console.log(boy.name + "年齡是" + boy.age);
  console.log(boy.name + "身高是" + boy.height);
  boy.weight && console.log(boy.name + "體重是" + boy.weight);
  boy.sex && console.log(boy.name + "性別是" + boy.sex);
  console.log(boy.say())
  console.log(boy.done())
};

screenResume(boy);
getResum(boy);

複製代碼

類的概念和使用

類的使用(構造一個類並實例化,而後調用其參數和方法)
class Car { 
   // 字段
   engine:string; 
   // 構造函數
   constructor(engine:string) { 
      this.engine = engine 
   }  
   // 方法
   disp():void { 
      console.log("函數中顯示發動機型號 : "+this.engine) 
   } 
} 
// 建立一個對象
var obj = new Car("XXSY1")
// 訪問字段
console.log("讀取發動機型號 : "+obj.engine)  
// 訪問方法
obj.disp()
複製代碼
類的繼承
class People{
    content="hi"
    sayHello(){
        return this.content
    }
}
class Man1 extends People{
    sayHello(){
        //重寫父類的方法時,可使用super關鍵字調用父類的方法或屬性
        return super.sayHello()+" 你好"
    }
    sayLove(){
        return "i love you"
    }
}
const goodess=new Man1()
console.log(goodess.sayHello())
console.log(goodess.sayLove())
複製代碼

須要注意的是子類只能繼承一個父類,TypeScript 不支持繼承多個類,但支持多重繼承

class Root { 
   str:string; 
} 
class Child extends Root {} 
class Leaf extends Child {} // 多重繼承,繼承了 Child 和 Root 類
var obj = new Leaf(); 
obj.str ="hello" 
console.log(obj.str)
複製代碼

類繼承後,子類能夠對父類的方法從新定義,這個過程稱之爲方法的重寫。 其中 super 關鍵字是對父類的直接引用,該關鍵字能夠引用父類的屬性和方法。

class PrinterClass { 
   doPrint():void {
      console.log("父類的 doPrint() 方法。") 
   } 
} 
class StringPrinter extends PrinterClass { 
   doPrint():void { 
      super.doPrint() // 調用父類的函數
      console.log("子類的 doPrint()方法。")
   } 
}
複製代碼
類的訪問類型
  • public 公共屬性類型,能夠在任何地方被訪問
  • private 受保護,能夠被其自身以及其子類和父類訪問,只能在類的內容使用,繼承也不能夠
  • protected 私有,只能被其定義所在的類訪問,只能在類的內部使用,繼承中也可使用
class Person1{
    private name:string;
    public sayHello(){
        //使用私有屬性不報錯
        console.log(this.name+'say hello')
    }
}
const person=new Person1()
//使用私有屬性報錯
person.name='ts'
console.log(person.name)
複製代碼
類的構造函數
class Person2{
    public name:string;
    constructor(name:string){
        this.name=name;
    }
}
class NewPerson2 extends Person2{
    constructor(public age:number){
        super("newts")
    }
}

const person2=new Person2('ts')
console.log(person2.name)
const newperson=new NewPerson2(18)
console.log(newperson.name)
console.log(newperson.age)

class People4{
    constructor(private _age:number){}
    get age(){
        return this._age
    }
    set age(newage:number){
        this._age=newage+10
    }
}
const onepeople=new People4(28)
console.log(onepeople.age)
onepeople.age=22
console.log(onepeople.age)
複製代碼
類的靜態方法

static 關鍵字用於定義類的數據成員(屬性和方法)爲靜態的,靜態成員能夠直接經過類名調用。

//靜態方法
class People5{
    static sayLove(){
        return 'I love you'
    }
}
const onepeople2=new People5()
console.log(People5.sayLove())
複製代碼
類的只讀屬性
//只讀屬性
class People6{
    public readonly _name:string
    constructor(name:string){
        this._name=name
    }
}
const person6=new People6('ts')
console.log(person6._name)
複製代碼
類和接口

類能夠實現接口,使用關鍵字 implements,並將其字段做爲類的屬性使用

class Man implements People {
  //implement關鍵字表示該類Man受到接口People的約束
  name = "zhangsan";
  age = 11;
  height = 180;
  say() {
    return "i can say";
  }
}
複製代碼

泛型

泛型的基本定義

在定義函數,接口,類的時候,不預先指定具體的類型,而在使用的時候在去指定類型的一種特徵 泛型的使用情景:

  • 當你的函數、接口或類將處理多種數據類型時;
  • 當函數、接口或類在多個地方使用該數據類型時。
//函數泛型格式以下 函數方法名<T>(參數):返回值
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 identity <T, U>(value: T, message: U) : T {
  console.log(message);
  return value;
}

console.log(identity<Number, string>(68, "Semlinker"));
複製代碼

泛型接口

相比以前定義的 identity 函數,新的 identity 函數增長了一個類型變量 U,但該函數的返回類型咱們仍然使用 T。若是咱們想要返回兩種類型的對象該怎麼辦呢?針對這個問題,咱們有多種方案,其中一種就是使用元組,即爲元組設置通用的類型

function identity <T, U>(value: T, message: U) : [T, U] {
  return [value, message];
}
複製代碼

更好的解決方案是使用泛型接口

interface Identities<V, M> {
  value: V,
  message: M
}
function identity<T, U> (value: T, message: U): Identities<T, U> {
  console.log(value + ": " + typeof (value));
  console.log(message + ": " + typeof (message));
  let identities: Identities<T, U> = {
    value,
    message
  };
  return identities;
}
console.log(identity(68, "Semlinker"));
//輸出
//68: number
//Semlinker: string
//{value: 68, message: "Semlinker"}
複製代碼

在上述的Identities接口中,咱們引入了變量類型V和M,來進一步說明有效的字母均可以用於表示類型變量,以後,以後就能夠將Identities接口做爲identity函數的返回類型

泛型類

在類中使用泛型,只須要在類名後面,使用<T,...>的語法定義任意多個變量類型

interface GenericInterface<U> {
  value: U
  getIdentity: () => U
}

class IdentityClass<T> implements GenericInterface<T> {
  value: T
  constructor(value: T) {
    this.value = value
  }
  getIdentity(): T {
    return this.value
  }
}
const myNumberClass = new IdentityClass<Number>(68);
console.log(myNumberClass.getIdentity()); // 68

const myStringClass = new IdentityClass<string>("Semlinker!");
console.log(myStringClass.getIdentity()); // Semlinker!
複製代碼

這裏以實例化myNumberClass爲例分析其調用過程

  • 在實例化IdentityClass對象時,傳入Number類型和構造函數參數值68
  • 以後在IdentityClass類中,類型變量T變成了Number類型
  • IdentityClass實現了GenericInterface<T>接口,此時T表示Number類型,所以等價於該類實現了GenericInterface<Number>接口
  • 而對於 GenericInterface<U> 接口來講,類型變量 U 也變成了 Number。這裏我有意使用不一樣的變量名,以代表類型值沿鏈向上傳播,且與變量名無關。

泛型約束

  1. 確保屬性存在

舉個例子,在處理字符串或者函數時,咱們回假設length屬性是可用的,因此當咱們直接輸出arg.length屬性的時候,是有可能報錯的 因此爲了保證編譯器知道T必定含有length屬性,咱們須要讓類型變量<T>extend一個含有咱們所須要屬性的接口

interface Length {
  length: number;
}

function identity<T extends Length>(arg: T): T {
  console.log(arg.length); // 能夠獲取length屬性
  return arg;
}
複製代碼

<T extends Length>這段代碼就告訴編譯器,咱們支持已經實現Length接口的任何類型,以後,當咱們使用不含有length屬性的對象做爲參數調用identity函數時,Ts編譯器就會提示想滾的錯誤信息

identity(68); // Error
// Argument of type '68' is not assignable to parameter of type 'Length'.(2345)
複製代碼

此外,咱們還可使用 , 號來分隔多種約束類型,好比:<T extends Length, Type2, Type3>。而對於上述的 length 屬性問題來講,若是咱們顯式地將變量設置爲數組類型,也能夠解決該問題,具體方式以下:

function identity<T>(arg: T[]): T[] {
   console.log(arg.length);  
   return arg; 
}

// or
function identity<T>(arg: Array<T>): Array<T> {      
  console.log(arg.length);
  return arg; 
}
複製代碼
  1. 檢查對象上的鍵是否存在

在具體使用以前要先了解一些keyof操做符,keyof在TypeScript2.1版本引入,該操做符能夠用於獲取某種類型的全部鍵,其返回類型是聯合類型

interface Person {
  name: string;
  age: number;
  location: string;
}

type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[];  // number | "length" | "push" | "concat" | ...
type K3 = keyof { [x: string]: Person };  // string | number
複製代碼

經過 keyof 操做符,咱們就能夠獲取指定類型的全部鍵,以後咱們就能夠結合前面介紹的 extends 約束,即限制輸入的屬性名包含在 keyof 返回的聯合類型中。具體的使用方式以下:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
複製代碼

在以上的 getProperty 函數中,咱們經過 K extends keyof T 確保參數 key 必定是對象中含有的鍵,這樣就不會發生運行時錯誤。這是一個類型安全的解決方案,與簡單調用 let value = obj[key] 不一樣。

enum Difficulty {
  Easy,
  Intermediate,
  Hard
}

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

let tsInfo = {
   name: "Typescript",
   supersetOf: "Javascript",
   difficulty: Difficulty.Intermediate
}
 
let difficulty: Difficulty = 
  getProperty(tsInfo, 'difficulty'); // OK

let supersetOf: string = 
  getProperty(tsInfo, 'superset_of'); // Error
//報錯信息
Argument of type '"superset_of"' is not assignable to parameter of type 
'"difficulty" | "name" | "supersetOf"'.(2345)
複製代碼

ts配置文件tsconfig.json的使用

使用步驟:

  1. tsc -init生成tsconfig.json(在終端中私用tsc命令,則會自動對該文件夾下的全部ts文件執行tsconcig.json)
  2. 配置tsconfig中的配置項
  • 使用"include"配置項指定要編譯的ts文件
  • exclude指定不編譯的文件
  • include包含的文件可使用exclude排除,被files白喊的文件不會被exclude排除
  • include能夠是目錄以及文件,而files只能是文件
  • files指定一個包含相對或絕對文件路徑的列表,include和exclude屬性指定一個文件glob匹配模式列表
相關文章
相關標籤/搜索