现在,我们可以将这个接口应用为 identities()
的返回类型,并稍稍修改返回类型去迎合它。我们还可以 console.log
这些参数和它们的类型,以便进一步说明:
function identities<T, U> (arg1: T, arg2: U): Identities<T, U> {
console.log(arg1 + ": " + typeof (arg1));
console.log(arg2 + ": " + typeof (arg2));
let identities: Identities<T, U> = {
id1: arg1,
id2: arg2
};
return identities;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
我们现在 identities()
所做的是将类型 T 和 U 传递到函数和 Identities
接口中,使我们能够定义与参数类型相关的返回类型。
注意:如果编译 TS 项目并查找泛型,则不会找到任何泛型。由于在 Javascript 中不支持泛型,所以在编译器生成的构建中不会看到泛型。泛型纯粹是用于编译时的开发安全网,它将确保代码的类型安全抽象。
泛型类
泛型类看上去与泛型接口差不多。 泛型类使用( <>
)括起泛型类型,跟在类名后面。
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
GenericNumber
类的使用是十分直观的,并且你可能已经注意到了,没有什么去限制它只能使用number
类型。 也可以使用字符串或其它更复杂的类型。
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };
alert(stringNumeric.add(stringNumeric.zeroValue, "test"));
与接口一样,直接把泛型类型放在类后面,可以帮助我们确认类的所有属性都在使用相同的类型。
我们在类那节说过,类有两部分:静态部分和实例部分。 泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。
泛型约束
你应该会记得之前的一个例子,我们有时候想操作某类型的一组值,并且我们知道这组值具有什么样的属性。 在loggingIdentity
例子中,我们想访问arg
的length
属性,但是编译器并不能证明每种类型都有length
属性,所以就报错了。
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
相比于操作any
所有类型,我们想要限制函数去处理任意带有.length
属性的所有类型。 只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性。 为此,我们需要列出对于T的约束要求。
为此,我们定义一个接口来描述约束条件。 创建一个包含 .length
属性的接口,使用这个接口和extends
关键字还实现约束:
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});
在泛型约束中使用类型参数
你可以声明一个类型参数,且它被另一个类型参数所约束。比如,
function find<T, U extends Findable<T>>(n: T, s: U) {
// ...
}
find (giraffe, myAnimals);
在泛型里使用类类型
在 TypeScript 使用泛型创建工厂函数时,需要引用构造函数的类类型。比如,
function create<T>(c: {new(): T; }): T {
return new c();
}
一个更高级的例子,使用原型属性推断并约束构造函数与类实例的关系。
class BeeKeeper {
hasMask: boolean;
}
class ZooKeeper {
nametag: string;
}
class Animal {
numLegs: number;
}
class Bee extends Animal {
keeper: BeeKeeper;
}
class Lion extends Animal {
keeper: ZooKeeper;
}
function findKeeper<A extends Animal, K> (a: {new(): A;
prototype: {keeper: K}}): K {
return a.prototype.keeper;
}
findKeeper(Lion).nametag; // typechecks!
标签:TypeScript
相关阅读 >>
更多相关阅读请进入《typescript》频道 >>

Vue.js 设计与实现 基于Vue.js 3 深入解析Vue.js 设计细节
本书对 Vue.js 3 技术细节的分析非常可靠,对于需要深入理解 Vue.js 3 的用户会有很大的帮助。——尤雨溪,Vue.js作者