TypeScript基础知识(二)

68 阅读3分钟

前言

该文章记录一些TS的一些基本知识,后续将会逐步增加,所有内容均从网上整理而来,加上自己得理解做一个整合,方便工作中使用。

一、泛型

泛型是可以在保证类型安全的前提下,让函数等与多种类型一起工作,从而实现复用,常用于:函数、接口、class

1.基础使用

//需求:传入进去是什么类型,返回的就是什么类型

function getStudentNo<TStudentNo>(no: TStudentNo) {
    return no
}
//<TStudentNo>    -> 声明泛型,类型别名一般用T开头
//no:TStudentNo   -> 使用泛型

let xiaoming = getStudentNo<number>(12)    //变量为number类型
let xiaoHong = getStudentNo<string>('001') //变量为string类型
//简化写法,调用时可以不加<类型>,TS会推断类型
let xiaoAi = getStudentNo(false) //变量为boolean类型

2.泛型的类型约束

//为什么要约束
function getStudentNo<TStudentNo>(no: TStudentNo) {
    console.log(no.length) //报错,因为TStudentNo是一个未知的类型
    return no
}

//1.指定更加明确的类型:TStudentNo类型的数组,list就是一个数组,可以使用数组的方法
//只能改成数组,限制太大
function getStudentNo<TStudentNo>(list: TStudentNo[]) {
    console.log(list.push())
    return list
}
let xiaoming = getStudentNo(['小明', '小红'])

//2.类型收缩-比较麻烦,先判断类型
function getStudentNo<TStudentNo>(list: TStudentNo) {
    if (typeof list === 'string') {
    list.slice(1, 2)
} else if (typeof list === 'number') {
    list * 100
}
    return list
}

//3.添加约束
//1) 定义接口
interface ILength {
    length: number
}
//2) 添加约束(给泛型找个爸爸)
function getStudentNo<TStudentNo extends ILength>(list: TStudentNo) {
    console.log(list.length)
    return list
}
let xiaoming = getStudentNo('abcd') //字符串有length属性,正常
let xiaoming2 = getStudentNo(123) //数字没有length属性,报错
let xiaoming3 = getStudentNo([1,2,3]) //数组有length属性,正常
let xiaoming4 = getStudentNo({name:'胡歌'}) //对象没有length属性,报错

//案例二
//1) 定义接口
interface ILength {
    say(): void
}
//2) 添加约束(给泛型找个爸爸)
function getStudentNo<TStudentNo extends ILength>(list: TStudentNo) {
    list.say()
    return list
}
//传入的参数其实类型和interface定义的一样
getStudentNo({
    say() {
      console.log('abc')
    }
})
//传入的参数其实类型和interface定义的一样
let obj: ILength = {
    say() {
      console.log(1231)
    }
}
getStudentNo(obj)

//疑问:其实使用type、interface约束函数的参数即可到达同样的效果
type ILength = {
    say(): void
}
function getStudentNo(list: ILength) {
    list.say()
    return list
}
getStudentNo({ say() { console.log(123) } })

3.多个泛型

//多个泛型
// 需求:定义一个函数,传入一个对象,再传入一个字符串属性名,然后返回属性值
function getProp(obj: object, key: string) {
    return obj[key] //报错
}

// 新语法:Tkey extends keyof TObject 意思就是Tkey要继承TObject的所有属性,
// 当函数传入参数key是参数obj中没有的属性时,就会报错
function getProp<TObject, Tkey extends keyof TObject>(obj: TObject, key: Tkey) {
    return obj[key] 
}
const result = getProp({ name: '胡歌' }, 'name')
const result2 = getProp({ name: '胡歌' }, 'sex') //报错,因为前面的参数中没有sex属性
let p1 = {
    name: '胡歌',
    sex: '男'
}
let p2 = {
    score: 99,
    hobby: '打游戏'
}
getProp(p1, 'name')
getProp(p1, 'sex')
getProp(p2, 'hobby')
getProp(p2, 'score')

let p3 = [1, 3, 4]
getProp(p3, 'length')

4.泛型接口

//泛型接口
interface IPerson<T> {
    id: number,
    name: T,
    hobby: T[]
}

let xiaoming: IPerson<string> = {
    id: 123,
    name: '小明',
    hobby: ['玩游戏']
}
let xiaohong: IPerson<number | string> = {
    id: 123,
    // name: '小明',      报错
    // hobby: ['玩游戏']  报错
    name: 123,
    hobby: [1, 2, '张三']
}