参考一些博客,整理的TS相关,供自己复习使用~
TS泛型
指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。 使用
<T>代表类型的变量,T只是约定用法,可以任意指定。
泛型无法知道具体的类型,所以无法操作它的属性和方法
function Test<T> (a:T):void {
console.log(a.length); // error
}
Test<string>('1')
在明确知道泛型中有哪些属性方法时,可以通过extends进行泛型约束,写在声明函数名的后面
interface hasLengthProp {
length : number;
}
function Test<T extends hasLengthProp>(a:T):void {
console.log(a.length);
}
泛型可以约束泛型 ---> 相当于泛型的继承
function test<T extends U,U>(a:T,b:U):void {
console.log(a);
}
test({a:1,b:2,c:3},{a:1,b:2})
在函数中使用泛型
案例一
function join<T> (a: T, b: T) {
return `${a} ${b}`;
}
join<number>(1, 2);
join<string>('1', '2');
// join<number>(1, '2');
// join<string>(1, '2');
案例二
function getArr<T>(arr: T[]) {
return arr;
}
getArr<number>([1, 2, 3]) //指定了number,那我的数组必须每一项也是number,如果不是就报错
getArr<string>(['g', 'q', 'f']) //同理这里指定了string
案例三
function getVal<T>(obj: T, k: keyof T){
return obj[k];
}
interface Person {
name: string;
age: number;
}
getVal<Person>({
name: 'gqf',
age: 29
}, 'age') // 这里的key值只能传name或者age,否则就会报错,这个就是泛型的力量
案例四
function manyTest<K, V>(a: K, b: V) {
return `${a} ${b}`
}
manyTest<number, string>(1, '2')
//泛型指定了第一个参数是数字,第二个参数是字符串,所以对应的参数也要这么传
在类中使用泛型
案例一
class DesignHero {
constructor(private skills: string[]){}
getSkill (index: number) {
console.log(this.skills[index])
return this.skills[index];
}
}
const hero = new DesignHero(['q', 'w', 'e', 'r']) // string[] 所以传入字符串数组
hero.getSkill(3)
案例二
class DesignHero {
constructor(private skills: number[]){} // 这行从string[]改成number[]
getSkill (index: number) {
console.log(this.skills[index])
return this.skills[index];
}
}
const hero = new DesignHero([1, 2, 3, 4]) // number[] 所以传入数字数组
hero.getSkill(3)
案例三
class DesignHero<T> {
constructor(private skills: T[]){}
getSkill (index: number) {
console.log(this.skills[index])
return this.skills[index];
}
}
const heroNumberSkill = new DesignHero<number>([1, 2, 3, 4])
heroNumberSkill.getSkill(1)
const heroStringSkill = new DesignHero<string>(['q', 'w', 'e', 'r'])
heroStringSkill.getSkill(2)
案例四
class DesignHero<T extends string | number> {
// 如果把继承的string | number 比如改成boolean, 那下面肯定就报错了
constructor(private skills: T[]){}
getSkill (index: number) {
console.log(this.skills[index])
return this.skills[index];
}
}
const heroNumberSkill = new DesignHero<number>([1, 2, 3, 4])
heroNumberSkill.getSkill(1)
const heroStringSkill = new DesignHero<string>(['q', 'w', 'e', 'r'])
heroStringSkill.getSkill(2)
案例五
interface Skill {
name: string;
canDamage: boolean; // 是否是直接造成伤害的技能
}
class DesignHero<T extends Skill> { // 规定了数组每一项的Skill技能,要遵循接口的格式,有name和canDamage字段
constructor(private skills: T[]){}
getSkillName (index: number) {
console.log(this.skills[index].name)
return this.skills[index].name;
}
}
const finalHero = new DesignHero([
{
name: '一技能',
canDamage: true,
},
{
name: '二技能',
canDamage: false,
},
{
name: '三技能',
canDamage: false,
},
{
name: '四技能',
canDamage: true,
}
])
finalHero.getSkillName(0)
在接口中使用
interface IResponseData<T>{
code: number;
message?: string;
data: T;
}
// 用户接口
interface IResponseUserData{
id: number;
username: string;
email: string;
}
// 文章接口
interface IResponseArticleData{
id: number;
title: string;
author: IResponseUserData;
}
async function getData<U>(url: string){
let response = await fetch(url);
let data: Promise<IResponseData<U>> = await response.json(); // 注意这里返回的是个Promise,然后我们根据不同的接口,指定不同的data数据格式
return data;
}
(async function(){
let userData = await getData<IResponseUserData>('/user');
userData.data.username;
let articleData = await getData<IResponseArticleData>('/article');
articleData.data.author.email;
})()