在代码开发中,使用泛型可以提高代码复用率和精简代码量。
TypeScript基础类型的泛型使用这里不做说明,网上很多资料。以下遇到的问题,文档中有说明,但没有明确的例子,开发中工具报的错误,不是很理解,记录错误解决如下。
在使用TypeScript中使用泛型,遇到如下问题:
interface TestData {
name: string;
num: number;
}
interface test<T> {
getData(): T;
}
abstract AbstractTest<T> implements test<T> {
data: T
constructor(data: T) {
this.data = data
}
abstract getData(): T;
}
class ATest<TestData> extends AbstractTest<T> {
constructor() {
let data: TestData = {
name: "bin",
num: 0
}
super(data)
}
getData(): T {
return this.data;
}
}
编译以上代码会出现如下问题:
不能将类型“{ name: string; num: number; }”分配给类型“TestData ”。
‘{ name: string; num: number; }’ is assignable to the constraint of type ‘TestData’, but ‘TestData’ could be instantiated with a different subtype of constraint ‘{}’.ts(2322)
上面的字面意思是:
{ name: string; num: number; }可以分配给受类型TestData约束类型,但是TestData也可以被约束的另一个子类型“{}”实例化。
从测试角度分析,T可以被多个类型初始化,不是唯一的TestData,因此不具备唯一性和准确性。
参照官方文档,实例如下:
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
若传入的T类型没有length,会在运行时出错。若要避免该问题,T类型继承一个一定有length的类型
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
loggingIdentity(3); // Error, number doesn't have a .length property
loggingIdentity({ length: 10, value: 3 });
按照官方文档理解,若要使泛型具备确定的属性,泛型需要继承指定的类型。以上demo改为一下:
interface TestData {
name: string;
num: number;
}
interface test<T> {
getData(): T;
}
abstract AbstractTest<T> implements test<T> {
data: T
constructor(data: T) {
this.data = data
}
abstract getData(): T;
}
class ATest<T extends TestData> extends AbstractTest<TestData> {
constructor() {
let data: TestData = {
name: "bin",
num: 0
}
super(data)
}
getData(): T {
return this.data;
}
}
let test = ATest<TestData>()
test.getData()
如此就不会出错了。
如果data赋值的对象多一个属性,也不会出错,比如
let data: = {
name: "bin",
num: 0,
test: 0
}
从测试情况看,为了避免类型错误,赋值给泛型对象的变量的属性必须要包含确定类型的全部属性,通过类型继承即可实现该需求,比如:
interface A {
a: string;
b: number;
}
<T extends A>
T就包含A的全部属性
如此,可以避免编译不知道泛型的具体类型,而出现运行时不具备需要的属性而出错。通过继承实现泛型类型的属性约束。