在代碼開發中,使用泛型可以提高代碼複用率和精簡代碼量。
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的全部屬性
如此,可以避免編譯不知道泛型的具體類型,而出現運行時不具備需要的屬性而出錯。通過繼承實現泛型類型的屬性約束。