TS泛型
泛型的作用
在函数中使用泛型
- 一个例子是,当一个函数的参数(当这个参数是对象时)可能具有多个类型时,首先我们可能想到联合类型来处理,但是当这些类型可能具有不同的属性的时候,联合类型就不能处理这种情况了,就需要使用泛型。
interface TypeA{
a: 1,
b: 2,
}
interface TypeB{
b: 1,
c: 1
}
function foo(a: TypeA | TypeB){
console.log(a.b) //变量a使用了联合类型TypeA | TypeB,因此a在取属性的时候,只能使用TypeA和TypeB都有的属性。
console.log(a.a) //类型检查出错,TypeB没有属性a
console.log(a.c) //类型检查出错,TypeA没有属性c
}
泛型可以在定义函数、接口或类时,不预先指定具体的类型,但在使用的时候指定类型的特性。
函数中使用泛型
在函数声明时使用泛型
-
在参数声明的括号前添加
-
函数声明使用泛型一般结合接口或类型别名来使用。
-
接口
- 接口可以用于指定函数重载。
interface fnType{ <T>(len: number,iniVal: T): Array<T>; <T>(len: string,iniVal: T): Array<T>; } let fn: fnType; fn = function<T>(len: number | string,iniVal: T): Array<T> { const arr = [] as Array<T>; if(typeof len === 'number') { for(let i = 0;i < len;i++) { arr[i] = iniVal; } return arr; } else{ return arr; } } fn(1,1) fn('1','2')
-
接口可以将写在接口名之后。
interface fnType<T>{ (len: number, iniVal: T): Array<T>; } let fn: fnType<any>; fn = function<T>(len: number,iniVal: T): Array<T>{ const arr = [] as T[]; for(let i = 0;i < len;i++) { arr[i] = iniVal; } return arr; } fn(1,1) fn(1,true)
-
类型别名或其他没有在接口中做函数声明的情况
type fnType1 = <T>(len: number, iniVal: T) => Array<T>;
type fnType<T> = (len: number, iniVal: T) => Array<T>; let fn: fnType<any>; fn = function<T>(len: number, iniVal: T): Array<T>{ const arr = [] as T[]; for(let i = 0;i < len;i++) { arr[i] = iniVal; } return arr; } fn(2,'2')
-
在给出函数体定义时使用泛型
- 在函数名后面添加,这个T将代指输入的参数的类型。
function createArr<T>(len: number,iniVal: T): Array<T>
{
const arr = []
for(let i = 0;i < len;i++)
{
arr[i] = iniVal;
}
return arr;
}
-
extends
-
extends的作用
-
当使用泛型时,如果没有为泛型T限制类型,那么不能对其取属性,extends用于为T限制类型。
- 使用了extends也相当于为泛型添加了约束,这时泛型只能接受包含某一属性的数据了。
interface objType<U>{ len: number; value: U; } function createArr<U,T extends objType<U>>(obj: T): Array<U>{ const len = obj.len; const val = obj.value; const arr = [] as Array<U>; for(let i = 0;i < len;i++) { arr[i] = val; } return arr; } const obj: objType<string> = { len: 2, value: 'val', } const obj1: objType<number> = { len: 2, value: 0, } console.log(createArr(obj)) console.log(createArr(obj1))
当T extends objType之后,泛型T只能接受包含objType中所有属性的接口、类型注解或类型别名(可以不限于objType,但必须包含,也就是objType是T的子集)。
-
-
-
定义多个泛型
-
TS支持在使用泛型时定义多个泛型。
function copy<T extends U, U>(source: U, target: T): T{ for(let attr in source) { target[attr] = (<T>source)[attr] } return target }
-
在调用泛型函数的时候指定泛型的值
- 调用含一个泛型的函数
function fn<T>(len: number,ini: T): Array<T>{
const res = [] as T[];
for(let i = 0;i < len;i++)
{
res[i] = ini;
}
return res;
}
fn<string>(2,'1') //相当于指定了泛型的类型,如果第二个参数不为string,那么会报错。
fn<number>(2,7)
- 调用含多个泛型的函数
function fn<T extends U,U>(target: T, source: U): T{
for(const attr in source)
{
target[attr] = (<T>source)[attr]
}
return target
}
console.log(fn<{a: number, b: string},{a: number}>({a: 2,b: 'a'},{a: 1}))
T extends U含义是,T中必须包含U中的所有属性,也就是U是T的子集。
在类中使用泛型
在类的声明中使用泛型
class State<T>{
value: T;
res: (val: T) => Array<T>;
}
let s = new State<number>();
s.value = 1
console.log(s)
s.res = <T>(val: T): Array<T> => {
const len = 2;
const res = [] as Array<T>;
for(let i = 0;i < len;i++)
{
res[i] = val;
}
return res;
}
console.log(s.res(2))
- TS的类的声明在编译后会留下额外代码 上面的TS代码编译后的js代码可以在下面看到
var State = /** @class */ (function () {
function State() {
}
return State;
}());
var s = new State();
s.value = 1;
console.log(s);
s.res = function (val) {
var len = 2;
var res = [];
for (var i = 0; i < len; i++) {
res[i] = val;
}
return res;
};
console.log(s.res(2));
可以看到State标识符指向一个IIFE函数表达式,这个IIFE中声明了一个具名函数State,并被当成值return出来。因此,我们知道函数State的词法作用域是IIFE的内部作用域,当我们使用State函数创建了一个对象s之后,形成了一个对IIFE作用域的闭包。
在类的实现时使用泛型
class C<T>{
value: T
constructor(val: T){
this.value = val
}
res(){
console.log(this.value)
}
}
let c1 = new C<number>(2)
console.log('c1',c1)
为泛型指定默认类型
class C<T = string>{
value: T
constructor(val: T){
this.value = val
}
res(){
console.log(this.value)
}
}
let c1 = new C<number>(2)
console.log('c1',c1)
当TS无法从参数推断出类型且我们在书写代码时没有指定类型时,默认类型才会起作用。 因此,下面这种用法也不会报错。因为TS可以从参数推断出泛型类型为Number。
class C<T = string>{
value: T
constructor(val: T){
this.value = val
}
res(){
console.log(this.value)
}
}
let c1 = new C(2)
console.log('c1',c1)