14泛型
# 泛型
- 泛型可以用来创建可重用的组件,一个组件可以支持多种类型的数据。
# 1、定义泛型
//这里的T可以传入任何类型数据,并返回相同的类型数据,相当于一个变量
function fn<T>(arg:T):T{
return arg
}
1
2
3
4
2
3
4
//练习
function fn<T>(arg: T): T {
return arg;
}
console.log(fn('hello 泛型'));
1
2
3
4
5
6
2
3
4
5
6
# 2、多个类型参数
//这里定义了两个不同的类型参数T、U,返回的值为U类型
function fn<T,U>(arg:T,arg2:U):U{
return arg2
}
1
2
3
4
2
3
4
//练习
function fn<T, U>(arg: T, arg2: U): U {
return arg2;
}
//console.log(fn(1, '2')); //2
console.log(fn('1', 2)); //2
1
2
3
4
5
6
7
2
3
4
5
6
7
# 3、泛型变量
- 如果我们想传入一个数组,然后再函数里面打印数组的长度会显示报错,因为
ts无法判断T类型有没有length属性
function fn<T>(arg:T){
console.log(arg.length)//类型T不存在length属性
}
1
2
3
2
3
- 这个时候我们可以把T类型作为数组的一部分
function fn<T>(arg:Array<T>){
console.log(arg.length)//不报错
}
1
2
3
2
3
//练习
function fn<T>(arg: Array<T>): void {
console.log(arg.length);
}
1
2
3
4
5
2
3
4
5
# 4、泛型接口
interface Fn<T>{
(arg:T):T
}
const fn:Fn<number> = (arg)=>arg
//这里把number传入接口当成参数使用
1
2
3
4
5
6
2
3
4
5
6
//练习
interface Fn<T> {
(arg: T): T;
}
let f: Fn<number> = function(arg) {
return arg;
};
console.log(f(1));
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 5、泛型类
- 泛型同样可以运用在类上。
class Arr{
private arr:number[] = []//arr属性为一个空数组,类型是全部数字的数组
public push(item:number){
this.arr.push(item)
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
- 使用泛型。
class Arr<T>{
private arr:T[] = []//arr数组里面的类型可以是任意的
public push(item:T){
this.arr.push(item)
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
//练习
class Person<T> {
constructor(name: T) {
this.name = name;
}
name: T;
}
// let p = new.Person(123);
let p = new Person('泛型-字符串');
console.log(p.name);
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 6、泛型约束
- 可以使用
extends来约束泛型
function fn<T extends number | string>(arg:T){
console.log(arg)
}
fn(1)//这里的参数只可以使用number或者是string类型
1
2
3
4
5
2
3
4
5
//练习
function fn<T extends number | string>(arg: T) {
console.log(arg);
}
fn('字符串');
fn(123);
// fn(true) //这里就报错了
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 7、泛型约束与索引类型
- 假如传入一个对象,再传入一个
key,最后打印出这个对象的value值
function fn(obj:object,key:string){
console.log(obj[key])//无法确定obj是否有key属性
}
1
2
3
2
3
- 应该这样做
//T被约束为对象类型,U被约束为T的字段
function fn<T extends object,U extends keyof T>(obj:T,key:U){
console.log(obj[key])//ok
}
let obj = {name:"小明",age:18}
fn(obj,"name")
1
2
3
4
5
6
7
2
3
4
5
6
7
//练习
// let obj{//代表【T】
// name:""//代表【U】
// }
function fn<T extends object, U extends keyof T>(obj: T, key: U) {
console.log(obj[key]);
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 8、多重类型约束
使用
&和|对泛型进行约束
interface a{
name:string
}
interface b{
age:number
}
function fn<T extends a & b>(arg:T){
console.log(arg)
}
fn({name:"小明",age:18})//必须同时符合a和b两种接口
interface a{
name:string
}
interface b{
age:number
}
function fn<T extends a | b>(arg:T){
console.log(arg)
}
fn({name:"小明"})//只需要符合a或者b其中一个即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//练习
interface Person {
name: string;
}
interface Student {
age: number;
}
function fn<T extends Person & Student>(arg: T): void {
console.log(arg);
}
fn({
name: '张三',
age: 18
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 9、约束为构造函数
function fn<T>(type:T):T{
return new type()//不可构造
}
1
2
3
2
3
正确做法
//写法1
function fn<T>(type:{new ():T}):T{
return new type()
}
class Person{
public name:string = "小明"
}
fn(Person)
//写法2
function fn<T,U>(arg:{new(U:string):T}):void{
console.log(new arg("小红"))
}
class Person{
constructor(name:string){
this.name = name
}
name:string
}
fn(Person)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
编辑 (opens new window)
上次更新: 2023/08/06, 00:38:41