大綱
本章主要講解一些ts的常規用法,涉及以下內容:
- interface: 介面
- class : 類
- function: 函式
- T : 泛型
之前因本人業務繁忙(太菜了 被拉去改bug了┭┮﹏┭┮), 所以拖更了,後邊會陸續補上, 還在踩坑的小夥伴,希望本文能給你們一些幫助 QAQ
介面
基本使用
定義: 用來集中約束資料型別,用關鍵詞interface來定義一個介面
interface People {
num:number,
country: string,
}
複製程式碼
使用介面:
// 這樣就會報錯: 因為約定的時候沒有name屬性
const getPeople = (people: People) => people.name
複製程式碼
- 定義可選屬性
interface User {
name: string,
age: number,
sex?: string // ? 表示可選的
}
複製程式碼
- 定義只讀屬性
interface User {
name: string,
age: number,
readonly weight: string, // readonly表示只讀
}
複製程式碼
- 定義函式屬性
interface User {
name: string,
age: number,
get: (sex: string) => string // 定義引數型別和返回值型別
}
// 或者直接使用函式介面
interface Func {
(sex: string) : string // 注意這裡的符號
}
interface User {
name: string,
age: number,
get: Func, // 使用介面
}
複製程式碼
注意點
有時候我們會遇到這樣的情況,當呼叫函式的時候,傳入的引數型別有可能是可選型別,舉個例子
- 定義介面
interface User1 {
name?: string,
}
複製程式碼
- 定義函式
const getUser = (user: User1): { result: string} => {
return {result: user.name }
}
複製程式碼
這時候會報型別錯誤, 因為返回值也可能是個void型別, 那如何避免?返回的時候也是可選即可
const getUser = (user: User1): { result?: string} => {
return {result: user.name }
}
複製程式碼
另外, 當我們呼叫的時候傳入的是額外的屬性比如傳入age屬性, 則需要as斷言
const username = getUser({age: 20} as User1)
複製程式碼
或者,我們可以在介面定義的時候傳入一個自定義屬性約束
interface User1 {
name?: string,
[propName: string]: any,// 屬性名字串型別, 這種條件下值可以是任意型別了
}
複製程式碼
通過上邊約束, 我們就可以實現這樣的一個資料型別約束,鍵key是變化的, key自增變化
const UserP = {
name: 'lili',
age: 20,
userClass: {
1: 'class1',
2: 'class2',
// .....
}
}
複製程式碼
- 定義約束
interface mark {
[name: number]: string
}
interface User2 {
name: string,
age: number,
userClass: mark
}
複製程式碼
介面繼承
直接貼程式碼,比較簡單, 也可以多繼承的
interface inter1 {
name: string
}
interface inter2 {
(age: number) : number
}
interface inter3 {
get: (name: string) => string
}
interface interAll extends inter1 {
add: (age: number) => number
}
// 多繼承
interface interAll extends inter1, inter2, inter3 {
add: (age: number) => number
}
複製程式碼
類class
抽象類
抽象類中只用於定義,定義的抽象方法,不會實現具體的方法,且不能例項化,只能作為基類,關鍵詞:abstract
abstract class Test {
add(): void { console.log('add') }
// 抽象方法不需要實現具體的方法
abstract remove(): string
}
// 直接例項化會導致錯誤
// const test = new Test()
複製程式碼
繼承抽象類
class Test1 extends Test {
// 這裡如果不實現remove方法就會報錯, 因為是抽象方法
remove() {
return 'remove'
}
}
複製程式碼
ts中的類關鍵詞
- public: 公共修飾詞 預設都是public 外部可以訪問到的
- protected: 外部無法訪問 內部和子類都可以訪問
- private: 私有修飾符 只有內部可以訪問
// class中的 關鍵詞
class Test2 {
// 公共修飾詞 預設都是public 外部可以訪問到的
public add() {
console.log('add')
}
// 外部無法訪問 內部和子類都可以訪問
protected remove() {
console.log('remove')
}
// 私有修飾符 只有內部可以訪問
private result() {
console.log('result')
this.remove() // 可以訪問
}
}
class Test3 extends Test2 {
change() {
this.add()
this.remove()
// 報錯 子類無法訪問
//this.result()
}
}
const test2 = new Test2()
test2.add()
//test2.remove() // 報錯
//test2.result() // 報錯
複製程式碼
作為初始化介面
class Test4 {
public name: string = 'lili'
public age: number = 20
public get(): string { return name }
}
const test4 = new Test4()
console.log(test4.get())
// test.name = 1 // 報型別錯誤 因為name是string型別
複製程式碼
函式
- 可選引數
const f1 = (a: string = 'f1', b? : number): void => console.log(a,b?b:'')
複製程式碼
- 剩餘引數 ...rest
const f2 = (a: string, ...rest: string[]): void => { }
複製程式碼
- 函式的過載
// 呼叫批次
function reloadFunc (name: string): { code: number }
function reloadFunc (name: string, age: number): { code: number }
// 函式實現
function reloadFunc (name: string, age?: number, sex?: string): { code: number } {
if(name) {
return { code: 0 }
}else if(age) {
return { code: 1 }
}else {
return { code: 2 }
}
}
reloadFunc('lili')
reloadFunc('lili', 20)
// reloadFunc('lili', 30, '男') 這一行會報一個錯誤: 期望是2個引數
複製程式碼
泛型
基本使用
泛型最大的作用在於靈活,對於程式碼複用有很大的用處,說白了,型別由呼叫者決定,從而實現的一種約束 定義: (T代表一種資料型別)
function testT<T>(name: T): T {
return name
}
// 呼叫, 傳入的是string型別 返回的約束也是該型別
testT('lili')
複製程式碼
同時支援多個型別的傳入:
function testT1<T, F>(name: T, age: F): [T, F] {
return [name, age]
}
複製程式碼
如果傳入的是陣列型別,需要返回陣列的某個屬性,比如length屬性
function testT2<T, F>(arr: Array<T>): number {
return arr.length // 如果沒指明陣列會報不存在length屬性錯誤 加上Array即可
}
複製程式碼
在介面中的應用
interface testT3<T> {
name: T
}
// 使用它
const test_t: testT3<number> = { name: 0 }
複製程式碼
泛型類
class TestT4<T> {
private name: T[] = []
public test(age: T): T {
return age
}
}
複製程式碼
呼叫就可以這樣
const test_t1 = new TestT4<number>()
test_t1.test(10)
複製程式碼
泛型繼承
也叫做泛型的約束,約束泛型只能在某個型別範圍內,使用關鍵詞extends
// extends 繼承某個型別
class TestT5<T extends Args> {
private name: T[] = []
public test(age: T): T {
return age
}
}
const test_t2 = new TestT5<number>() // 這裡就必須是這兩種型別了
複製程式碼
泛型物件索引
比如我們傳入一個物件型別,這種情況下編譯器是懵逼的 不知道obj有沒有key(預設是{})屬性且還不知道key的型別
function testT6<T>(obj: T, key: number) {
return obj[key]
}
複製程式碼
改造一下,讓它繼承物件的型別,在用屬性繼承(keyof)這個型別,可能難理解, 直接看程式碼
function testT6<T extends object, U extends keyof T>(obj: T, key: U) {
return obj[key]
}
複製程式碼
泛型繼承介面
泛型並不支援多繼承,也就是說T extends A,B,C 這樣是行不通的, 但是我們可以先用介面實現多繼承,然後在繼承這個介面, 也就是說 interface A extends B,C,D 然後 T extends A
interface testFunc extends A,B,C{
name: string,
age: number,
}
function testT7<T extends testFunc>(obj: T) {
return obj
}
複製程式碼
泛型建構函式約束
如果傳入的引數是一個建構函式比如:
function testT8<T>(func: T) {
return new func() // 這樣會報錯, 因為不知道是構造型別
}
複製程式碼
改造一下: ( new( ) )
function testT8<T>(func: {new(): T}): T {
return new func()
}
複製程式碼
如果對大家有幫助記得點贊個~ , 如有錯誤請指正, 我們一起解決,一起進步 ~