目錄
- 函數(shù)類型
- 函數(shù)聲明
- 函數(shù)類型表達式
- 可選參數(shù)
- 任意個數(shù)的參數(shù)
- 接口(interface)
- 定義接口
- 使用接口
- 選成員 & 只讀成員 & 動態(tài)成員
- 類
- 需要對類的屬性與方法進行聲明
- 類成員訪問修飾符(public/private/protected)
- 定義一個構(gòu)造函數(shù)
- 初始化實例對象并訪問構(gòu)造函數(shù)成員
- 創(chuàng)建子類繼承構(gòu)造函數(shù)并訪問其成員
- 類的構(gòu)造函數(shù)被私有化
- 類的只讀屬性
- 類與接口
- 定義接口
- 實現(xiàn)接口
- 抽象類
- 抽象類定義
- 子類繼承
- 泛型
- 定義泛型參數(shù)
- 調(diào)用時傳入泛型參數(shù)的類型
- TypeScript學習地圖
函數(shù)類型
函數(shù)的輸入和輸出進行約束亩进,及參數(shù)和返回值
函數(shù)聲明
// 參數(shù)的類型和返回值的類型
function func1(a: number, b: number): string {
return 'func1'
}
// 參數(shù)類型和個數(shù)是固定的灵汪,否則報錯
func1(100, 200)
函數(shù)類型表達式
// 普通函數(shù)
const func4 = function (a: number, b: number): string {
return 'func2'
}
// 使用箭頭函數(shù)
const func5: (a: number, b:number) => string = function(a, b) {
return 'func2'
}
可選參數(shù)
可選參數(shù)一定要在必選參數(shù)后面牺汤,放在函數(shù)最后咳短。
// 可以在b后面添加問號表示可選,也可以直接設置默認值评也,也可以不用傳
function func2(a: number, b: number = 10, c?: number): string {
return 'func1'
}
func1(100)
任意個數(shù)的參數(shù)
使用ES6
的rest
操作符
function func3(a: number, b: number = 10, ...rest: number[]): string {
return 'func1'
}
func1(100,200,300,400)
接口(interface)
接口攒磨,是一種規(guī)范、契約蜗字,約定對象的結(jié)構(gòu)打肝。
接口是用來約束一個對象的結(jié)構(gòu),我們要使用這個接口挪捕,就要遵循其全部的約定粗梭。
接口最直觀的體現(xiàn)就是對象應該有哪些成員以及成員的類型都是什么樣的?
定義接口
// 定義一個接口,里面確定要有兩個成員级零,且都是字符串類型
interface Post {
title: string // 結(jié)尾可以使用逗號分隔断医,也可以使用分號去分割,還可以省略
content: string
}
使用接口
// 使用的時候聲明參數(shù)是Post類型奏纪,里面使用的時候不擔心沒有值
function printPost (post: Post) {
console.log(post.title)
console.log(post.content)
}
// title和content任何一個沒有傳或者不是字符串都會報錯
printPost({
title: 'this is a title',
content:'this is a content'
})
可選成員 & 只讀成員 & 動態(tài)成員
- 可選成員 : 定義接口的時候添加問號鉴嗤,傳參的時候可有可無
interface Post {
title: string
content: string
subtitle?: string // 可選成員,可有可無,string or undefined
}
// 下面不傳subtitle不會報錯
const hello: Post = {
title: 'this is a title',
content:'this is a content'
}
-
只讀成員 :定義接口的時候前面添加
readonly
關(guān)鍵詞序调,一經(jīng)定義不能修改
interface Post {
title: string
content: string
subtitle?: string
readonly summary: string //只讀成員醉锅,一經(jīng)定義不能更改
}
const hello: Post = {
title: 'this is a title',
content:'this is a content',
summary: 'this is a summary'
}
hello.summary = 'hello' // 報錯
- 動態(tài)成員 :不確定有哪些成員,自己定義添加发绢,一般這種都存在動態(tài)對象里面硬耍,例如程序中的緩存對象。
因為不知道有哪些成員名稱边酒,所以Cache
里面使用[]
经柴,指定鍵prop
的類型是string
,值的類型是number
interface Cache {
[prop: string] : number
}
const cache: Cache = {}
cache['hello'] = 1
cache['hi'] = 2
類
類用來描述一類具體事物的抽象特征甚纲。TypeScript
增強了class
的相關(guān)語法口锭,訪問修飾符以及抽象類的概念等...
下面看一下TypeScript
新增的內(nèi)容:
需要對類的屬性與方法進行聲明
目的是為了給屬性和方法做類型標注
class Person {
// 需要對類的屬性進行聲明,可以添加默認值介杆,也可以不添加
// 兩者有一個沒有寫鹃操,都會報錯
name: string = 'init name'
age: number
constructor (name: string, age: number) {
// 如果不加聲明,這里直接使用會報錯春哨,因為在TypeScipt需要明確屬性荆隘,而不是動態(tài)添加
this.name = name
this.age = age
}
// 方法這些和之前是一樣的,也要添加類型注解
sayHi (msg: string): void {
console.log(`I am ${this.name}, ${msg}`)
}
run (): void {
this.sayHi('I am happy!')
}
}
類成員訪問修飾符(public/private/protected)
- | public | private | protected |
---|---|---|---|
內(nèi)部訪問 | 可 | 可 | 可 |
外部訪問 | 可 | 不可 | 不可 |
子類訪問 | 可 | 不可 | 可 |
1. 定義一個構(gòu)造函數(shù)
class Person {
// 默認是public赴背,加不加效果一樣椰拒,建議去加
public name: string = 'init name'
// age屬性是個私有屬性晶渠,私有屬性可以在函數(shù)內(nèi)部通過this.age去訪問
private age: number
// 受保護的,外界成員不可訪問燃观,子類成員可以訪問
protected gender: boolean
constructor (name: string, age: number) {
this.name = name
this.age = age
this.gender = true
}
sayHi (msg: string): void {
console.log(`I am ${this.name}, ${msg}`)
console.log(this.age) //自己內(nèi)部訪問私有屬性是沒有問題的
console.log(this.gender) //自己內(nèi)部訪問受保護屬性是沒有問題的
}
}
2. 初始化實例對象并訪問構(gòu)造函數(shù)成員
const xm = new Person('xm', 18)
console.log(xm.name)
console.log(xm.age) // 報錯褒脯,Property 'age' is private and only accessible within class 'Person'
console.log(xm.gender) // 報錯,Property 'gender' is protected and only accessible within class 'Person' and its subclasses.
3. 創(chuàng)建子類繼承構(gòu)造函數(shù)并訪問其成員
//定義一個Student類繼承Person
class Student extends Person {
constructor(name: string, age: number) {
super(name, age)
console.log(this.gender)
console.log(this.age) // 報錯缆毁,私有成員不能訪問
console.log(this.name)
}
}
類的構(gòu)造函數(shù)被私有化
-
private
: 如果類的構(gòu)造函數(shù)被私有化番川,那么不能被實例化和繼承,這個時候只能在這個類的內(nèi)部添加一個靜態(tài)方法脊框,通過靜態(tài)方法添加實例颁督。 -
protected
: 如果類的構(gòu)造函數(shù)被受保護,那么不能實例化浇雹,但是可以繼承沉御。
class Student extends Person {
private constructor(name: string, age: number) {
super(name, age)
console.log(this.gender)
console.log(this.name)
}
// 可以定義一個方法內(nèi)部實例化
static create (name: string, age: number) {
return new Student(name, age)
}
}
const xm = Student.create('xm', 18)
console.log(xm.name)
類的只讀屬性
在屬性前添加修飾符readonly
,如果有訪問修飾符昭灵,那么就跟在修飾符的后面.只讀屬性必須在聲明時或構(gòu)造函數(shù)里被初始化吠裆。
class Person {
public name: string = 'init name'
private age: number
// 如果有訪問修飾符,那么就跟在修飾符的后面
protected readonly gender: boolean
constructor (name: string, age: number) {
this.name = name
this.age = age
this.gender = true
}
sayHi (msg: string): void {
console.log(`I am ${this.name}, ${msg}`)
console.log(this.gender = false) // Cannot assign to 'gender' because it is a read-only property.
}
run (): void {
this.sayHi('I am happy!')
}
}
let xm = new Person('xm', 18)
xm.gender = 'false' // 報錯
類與接口
類與類之間的公共特征一般會用接口去抽象
比如下面兩個不同的類烂完,但是都有eat
和run
兩個相同的方法硫痰,可以用接口約束兩個類中公共的部分
class Person {
eat (food: string): void {
console.log(`優(yōu)雅進餐:${food}`)
}
run (distance: number) {
console.log(`直立行走:${distance}`)
}
}
class Animal {
eat (food: string): void {
console.log(`不優(yōu)雅進餐:${food}`)
}
run(distance: number) {
console.log(`爬行:${distance}`)
}
}
定義接口
// 可以定義一個接口實現(xiàn)一個能力,然后讓一個類實現(xiàn)多個接口
interface Eat {
eat (food: string): void
}
interface Run {
run (distance: number): void
}
實現(xiàn)接口
// Person和Animal要實現(xiàn)接口窜护,如果里面少了接口對應的方法,就會報錯效斑。
class Person implements Eat, Run{
eat (food: string): void {
console.log(`優(yōu)雅進餐:${food}`)
}
run (distance: number) {
console.log(`直立行走:${distance}`)
}
}
class Animal implements Eat, Run{
eat (food: string): void {
console.log(`不優(yōu)雅進餐:${food}`)
}
run(distance: number) {
console.log(`爬行:${distance}`)
}
}
抽象類
- 抽象類與接口有些類似,也是約束子類中必須要有哪些成員柱徙,不同的是抽象類里面可以包含一些具體的實現(xiàn)
- 抽象類只能繼承缓屠,不能實例化對象
- 抽象類中可以定義一些抽象方法
- 抽象方法不需要方法體,當父類中有抽象方法的時候护侮,子類必須要實現(xiàn)抽象方法
抽象類定義
// 添加abstract關(guān)鍵詞之后就成為了抽象類
abstract class Animal {
eat (food: string): void {
console.log(`不優(yōu)雅進餐:${food}`)
}
// 抽象類中可以定義一些抽象方法敌完,也需要關(guān)鍵詞abstract
abstract run (distance: number): void
}
子類繼承
class Dog extends Animal {
// 可以在VSCode環(huán)境點擊Dog使用快速修復自動生成代碼實現(xiàn)
// 這里實現(xiàn)了抽象類中的run抽象方法
run(distance: number): void {
console.log('爬行', distance)
}
}
// 子類實例化
const d = new Dog()
d.eat('糧食')
d.run(100)
泛型
我們在定義函數(shù)、接口或者類的時候沒有去指定類型羊初,只有當使用的時候才去指定類型的一種特征滨溉。
其目的 就是為了極大程度復用我們的代碼
舉個例子:
下面是傳入長度和值,返回一個數(shù)組
// 參數(shù)長度是number類型长赞,value是number類型晦攒,返回的是number類型的數(shù)組
function createArray (length: number, value: number): number[] {
const arr = Array<number>(length).fill(value)
return arr
}
// 下面?zhèn)魅雲(yún)?shù)可以獲得三個值為100的數(shù)字類型的數(shù)組
const res = createArray(3, 100) // res => [100, 100, 100]
上面的代碼有個缺陷是只能返回數(shù)字類型的數(shù)組,如果換成其他類型就會報錯得哆,如何進行修改?
定義泛型參數(shù)
- 函數(shù)名后面使用尖括號脯颜,里面定義泛型參數(shù)
- 一般泛型參數(shù)都用大寫的
T
作為名稱,函數(shù)中不明確的類型都用T
去代表
function createArray <T> (length: number, value: T): T[] {
const arr = Array<T>(length).fill(value)
return arr
}
調(diào)用時傳入泛型參數(shù)的類型
- 調(diào)用時在函數(shù)名后面用尖括號內(nèi)部填入?yún)?shù)的類型
// 下面可以填充字符串類型或者數(shù)字類型都可以
const res = createArray<string>(3, 'foo')
const res1 = createArray<number>(3, 100)
總結(jié) 就是泛型參數(shù)將定義時不能明確的參數(shù)用一個T
來代替贩据,使用的時候指定T
的類型