TypeScript 入門知識點總結

TypeScript 介紹

什麼是 TypeScript

是 JavaScript 的一個超集,它能夠編譯成純 JavaScript。編譯出來的 JavaScript 能夠運行在任何瀏覽器上,主要提供了類型系統對 ES6 的支持node

爲何選擇 TypeScript

  • 增長了代碼的可維護性
  • 包容性強,支持 ES6 語法,.js文件直接重命名爲.ts便可
  • 兼容第三方庫,即便第三方庫不是 TypeScript 寫的,也能夠經過單獨編寫類型文件供識別讀取
  • 社區活躍,目前三大框架還有愈來愈多的庫都支持 TypeScript 了

TypeScript 只會在編譯的時候對類型進行靜態檢查,若是發現有錯誤,編譯的時候就會報錯。git

安裝 TypeScript

  1. 全局安裝 TS
npm i -g typescript
  1. 查看 TypeScript 版本號
tsc -v

我當前版本爲 Version 4.0.2github

  1. 初始化生成 tsconfig.json 文件
tsc --init
  1. 在 tsconfig.json 中設置源代碼目錄和編譯生成 js 文件的目錄
"outDir": "./dist",
"rootDir": "./src"
  1. 監聽 ts 文件的變化,每當文件發生改變就自動編譯
tsc -w

以後你寫的 ts 文件編譯錯誤都會直接提示,若是想運行文件,就到 /dist目錄下找相應的 js 文件,使用 node 運行便可typescript

ts-node 安裝

固然這樣其實也挺麻煩,咱們想直接運行 TS 文件, 這時能夠藉助ts-node插件npm

全局安裝json

npm install -g ts-node

找到文件路徑,運行便可數組

ts-node demo.ts

基礎類型

Number 類型

let num: number = 2

Boolean 類型

let isShow: boolean = true

String 類型

let str: string = 'hello'

Array 類型

let arr1: number[] = [1, 2, 3]
let arr2: Array<number> = [2, 3, 4]

Any 類型

let foo: any = 'hello'
foo = 12
foo = false

Null 和 Undefined 類型

null 和 undefined 能夠賦值給任意類型的變量瀏覽器

let test1: undefined = undefined
let test2: null = null
let test3: number
let test4: string
test3 = null
test4 = undefined

Void 類型

void 類型像是與 any 類型相反,它表示沒有任何類型。當一個函數沒有返回值時,其返回值類型是 void框架

let test5: void = undefined // 聲明一個 void 類型的變量沒有什麼用,由於它的值只能爲 undefined 或 null
function testFunc(): void {} // 函數沒有返回值

Never 類型

never 類型表示的是那些永不存在的值的類型。dom

function bar(): never {
  throw new Error('never reach')
}

Unknown 類型

全部類型均可以賦值給 any,全部類型也均可以賦值給 unknown。

let value: unknown
value = 123
value = 'Hello'
value = true

let value1: unknown = value
let value2: any = value
let value3: boolean = value // Error
let value4: number = value // Error
let value5: string = value // Error
let value6: object = value // Error
let value7: any[] = value // Error
let value8: Function = value // Error

unknown 類型只能被賦值給 any 類型和 unknown 類型自己。

Tuple 類型

數組合並了相同類型的對象,而元組(Tuple)合併了不一樣類型的對象。元組表示一個數量和類型都已知的數組

let tupleArr1: [string, number] = ['hello', 10]
// let tupleArr2: [string, number] = [10, 'hello'] // Error

Enum 類型

使用枚舉能夠定義一些帶名字的常量。 TypeScript 支持數字的和基於字符串的枚舉。

enum Season {
    Spring,
    Summer,
    Autumn,
    Winter,
  }
  let a: Season = Season.Spring
  let b: Season = Season.Summer
  let c: Season = Season.Autumn
  let d: Season = Season.Winter
  console.log(a, b, c, d) // 0 1 2 3
}

函數類型

函數聲明

// JS
function func1(x, y) {
  return x + y
}
// TS
function func2(x: number, y: number): number {
  return x + y
}

函數表達式

在 TypeScript 的類型定義中,=> 用來表示函數的定義,左邊是輸入類型,須要用括號括起來,右邊是輸出類型。

// JS
let func3 = function (x, y) {
  return x + y
}
// TS 第一種方式
let func4 = function (x: number, y: number): number {
  return x + y
}
// TS 第二種方式
// => 用來表示函數的定義,左邊是輸入類型,須要用括號括起來,右邊是輸出類型。
let func5: (x: number, y: number) => number = function (x: number, y: number): number {
  return x + y
}

接口定義函數的形狀

採用函數表達式|接口定義函數的方式時,對等號左側進行類型限制,能夠保證之後對函數名賦值時保證參數個數、參數類型、返回值類型不變。

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

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

可選參數

對於 TS 的函數,輸入多餘的(或者少於要求的)參數,是不容許的,那麼該怎麼設置可選參數呢?,咱們能夠在聲明以後加一個問號

function getName1(firstName: string, lastName?: string) {
  // 可選參數必須接在必需參數後面
  if (lastName) {
    return `${firstName} ${lastName}`
  } else {
    return firstName
  }
}
let name1 = getName1('jacky')
let name2 = getName1('jacky', 'lin')
console.log(name1, name2)

參數默認值

function getName2(firstName: string = 'monkey', lastName: string) {
  return `${firstName} ${lastName}`
}
console.log(getName2('jacky', 'Lin'))
console.log(getName2(undefined, 'Lin')) // monkey Lin

void 和 never 類型

當函數沒有返回值時,能夠用 void 來表示。

當一個函數永遠不會返回時,咱們能夠聲明返回值類型爲 never

function func6(): void {
  // return null
}

function func7(): never {
  throw new Error('never reach')
}

剩餘參數

function push1(arr, ...items) {
  items.forEach(function (item) {
    arr.push(item)
  })
}
let a: any[] = []
push1(a, 1, 2, 3)

function push2(arr: any[], ...items: any[]): void {
  items.forEach(function (item) {
    arr.push(item)
  })
}
let b: any[] = []
push1(b, 1, 2, 3, '5')

函數參數爲對象(解構)時

// js寫法
function add({ one, two }) {
  return one + two
}

const total = add({ one: 1, two: 2 })

// ts 寫法
function add1({ one, two }: { one: number; two: number }): number {
  return one + two
}

const three = add1({ one: 1, two: 2 })

函數重載

重載容許一個函數接受不一樣數量或類型的參數時,做出不一樣的處理。

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('')
  }
}

類型斷言

TypeScript 容許你覆蓋它的推斷,而且能以你任何你想要的方式分析它,這種機制被稱爲「類型斷言」。

TypeScript 類型斷言用來告訴編譯器你比它更瞭解這個類型,你知道你本身在幹什麼,而且它不該該再發出錯誤。

interface Cat {
  name: string
  run(): void
}

interface Fish {
  name: string
  swim(): void
}

// 只能訪問共有的屬性
function getName(animal: Cat | Fish): string {
  return animal.name
}

// 將 animal 斷言成 Fish 就能夠解決訪問 animal.swim 時報錯的問題
function isFish(animal: Cat | Fish): boolean {
  if (typeof (animal as Fish).swim === 'function') {
    return true
  }
  return false
}

// 任何類型均可以被斷言爲 any
;(window as any).randomFoo = 1
// 類型斷言第一種方式:"尖括號"語法
let value1: any = 'hello'
let value1Length: number = (<string>value1).length

// 類型斷言第二種方式:as
let value2: any = 'world'
let value2Length: number = (value2 as string).length

存取器

class Animal {
  constructor(name: string) {
    this.name = name
  }
  // getter
  get name() {
    return '名字'
  }
  // setter
  set name(value: string) {
    console.log('setter: ' + value)
  }
}

let animal = new Animal('monkey')
console.log(animal.name) // monkey
animal.name = 'mk' // setter: mk

訪問修飾符

  • public 修飾的屬性或方法是公有的,能夠在任何地方被訪問到,默認全部的屬性和方法都是 public 的
  • private 修飾的屬性或方法是私有的,不能在聲明它的類的外部訪問
  • protected 修飾的屬性或方法是受保護的,它和 private 相似,區別是它在子類中也是容許被訪問的
class Person {
  public name
  private age
  protected sex
  public constructor(name: string, age: number, sex: string) {
    this.name = name
    this.age = age
    this.sex = sex
  }
}

let person1 = new Person('jacky', 22, 'man')
person1.name = 'monkey' // name值能夠訪問且修改
// person1.age // Property 'age' is private and only accessible within class 'Person'.
// person1.sex // Property 'sex' is private and only accessible within class 'Person'.

class Person1 extends Person {
  constructor(name: string, age: number, sex: string) {
    super(name, age, sex)
    // console.log(this.name, this.age, this.sex) // Property 'age' is private and only accessible within class 'Person'.
  }
}

參數屬性

同時給類中定義屬性的同時賦值

class Animal3 {
  public name
  constructor(name: string) {
    this.name = name
  }
}
console.log(new Animal3('animal3').name) // animal3

class Animal2 {
  constructor(public name: string) {} // 簡潔形式
}
console.log(new Animal2('animal2').name) // animal2
  • readonly 只讀屬性
class Animal4 {
  readonly name
  constructor(name: string) {
    this.name = name
  }
}
let animal4 = new Animal4('animal4')
// animal4.name = '5' // Cannot assign to 'name' because it is a read-only property

抽象類

// 抽象類是行爲的抽象,通常來封裝公共屬性的方法的,不能被實例化
abstract class CommonAnimal {
  name: string
  abstract speak(): void
}

static

class Animal5 {
  static sayHi() {
    console.log('Hello Animal5')
  }
}
Animal5.sayHi()

聯合類型

聯合類型(Union Types)表示取值能夠爲多種類型中的一種。使用一個|分割符來分割多種類型

let foo: string | number | boolean
foo = 'test'
foo = 3
foo = true

交叉類型

interface IPerson {
  id: string
  age: number
}

interface IWorker {
  companyId: string
}

type IStaff = IPerson & IWorker

const staff: IStaff = { id: '007', age: 24, companyId: '1' }

類型別名

type Message = string | string[]

let getMsg = (message: Message) => {
  return message
}

type Weather = 'SPRING' | 'SUMMER' | 'AUTUMN' | 'WINTER'
let weather1: Weather = 'SPRING'
let weather2: Weather = 'AUTUMN'

接口

對象的形狀

interface Person1 {
  name: string
  age: number
}
let person1: Person1 = {
  name: 'jacky',
  age: 23,
}

描述行爲的抽象

interface AnimalLike {
  eat(): void
  move(): void
}

interface PersonLike extends AnimalLike {
  speak(): void
}

class Human implements PersonLike {
  speak() {}
  eat() {}
  move() {}
}

含構建函數做參數的寫法

class Animal1 {
  constructor(public name: string) {}
  age: number
}

class Animal2 {
  constructor(public age: number) {}
}

interface WithNameClass {
  new (name: string): Animal1
}

function createClass(classname: WithNameClass, name: string) {
  return new classname(name)
}

let instance1 = createClass(Animal1, 'monkey')
// let instance2 = createClass(Animal2, 'monkey') // 沒有name屬性則報錯

其它任意屬性

interface Person2 {
  readonly id: number
  [propName: string]: any //任意屬性
}

泛型

泛型是指定義函數、接口或類的時候,不預先指定具體的類型,而在使用的時候再指定類型的一種特性;一般用 T 表示,但不是必須使用改字母,只是常規,一般還有其餘經常使用字母:

  • T(Type):表示一個 TypeScript 類型
  • K(Key):表示對象中的鍵類型
  • V(Value):表示對象中的值類型
  • E(Element):表示元素類型

泛型類

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

let generic = new GenericNumber<number>()
generic.name = 123

泛型數組

  • 寫法一
function func<T>(params: T[]) {
  return params
}
func<string>(['1', '2'])
func<number>([1, 2])
  • 寫法二
function func1<T>(params: Array<T>) {
  return params
}
func1<string>(['1', '2'])
func1<number>([1, 2])

泛型接口

能夠用來約束函數

interface Cart<T> {
  list: T[]
}
let cart: Cart<number> = { list: [1, 2, 3] }

泛型別名

type Cart2<T> = { list: T[] } | T[]
let c1: Cart2<number> = { list: [1, 2, 3] }
let c2: Cart2<number> = [1, 2, 3]

泛型接口 VS 泛型別名

  • 接口建立了一個新的名字,它能夠在其餘任意地方被調用。而類型別名並不建立新的名字
  • 類型別名不能被 extends 和 implements,這時咱們應該儘可能使用接口代替類型別名
  • 當咱們須要使用聯合類型或者元組類型的時候,類型別名會更合適

多個泛型

// 不借助中間變量交換兩個變量的值
function swap<T, P>(tuple: [T, P]): [P, T] {
  return [tuple[1], tuple[0]]
}

let ret = swap([1, 'a'])
ret[0].toLowerCase()
ret[1].toFixed(2)

默認泛型

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

泛型約束(繼承)

interface WithLength {
  length: number
}
// extends 來繼承
function logger<T extends WithLength>(val: T) {
  console.log(val.length)
}
logger('hello')
logger([1, 2, 3])
// logger(true) // error 沒有length屬性

泛型工具類型

爲了方便開發者 TypeScript 內置了一些經常使用的工具類型,好比 Partial、Required、Readonly、Pick 等。它們都是使用 keyof 實現。

keyof 操做符能夠用來一個對象中的全部 key 值。

interface Person1 {
  name: string
  age: number
  sex?: string
}
type PersonKey = keyof Person1 // 限制 key 值的取值
function getValueByKey(p: Person1, key: PersonKey) {
  return p[key]
}

內置的工具類型

// type Partial<T> = {[P in keyof T]?: T[P]}
type PersonSearch = Partial<Person> // 所有變可選

// type Required<T> = { [P in keyof T]-?: T[P] }
type PersonRequired = Required<Person> // 所有變必選

// type ReadOnly<T> = { readonly [P in keyof T]: T[P] }
type PersonReadOnly = Readonly<Person> // 所有變只讀

// type Pick<T, K extends keyof T>  = {[P in K]: T[P]}
type PersonSub = Pick<Person, 'name'> // 經過從Type中選擇屬性Keys的集合來構造類型。

類數組

let root = document.getElementById('root')
let children: HTMLCollection = root!.children // ! 表明非空斷言操做符
let childNodes: NodeListOf<ChildNode> = root!.childNodes

類型保護

更明確的判斷某個分支做用域中的類型,主要嘗試檢測屬性、方法或原型,以肯定如何處理值。

typeof

function double(input: string | number | boolean): number {
  // 基本數據類型的類型保護
  if (typeof input === 'string') {
    return input.length
  } else if (typeof input === 'number') {
    return input
  } else {
    return 0
  }
}

instanceof

class Monkey {
  climb: string
}
class Person {
  sports: string
}
function getAnimalName(animal: Monkey | Person) {
  if (animal instanceof Monkey) {
    console.log(animal.climb)
  } else {
    console.log(animal.sports)
  }
}

in

class Student {
  name: string
  play: string[]
}
class Teacher {
  name: string
  teach: string
}
type SchoolRole = Student | Teacher
function getRoleInformation(role: SchoolRole) {
  if ('play' in role) {
    console.log(role.play)
  }
  if ('teach' in role) {
    console.log(role.teach)
  }
}

自定義類型保護

好比有時兩個類型有不一樣的取值,也沒有其餘能夠區分的屬性

interface Bird {
  leg: number
}
interface Dog {
  leg: number
}
function isBird(x: Bird | Dog): x is Bird {
  return x.leg === 2
}
function getAnimal(x: Bird | Dog): string {
  if (isBird(x)) {
    return 'bird'
  } else {
    return 'dog'
  }
}

上述完整代碼示例:typescript-tutorial


相關文章
相關標籤/搜索