軟件工程中,咱們不只要建立一致的定義良好的API,同時也要考慮可重用性。 組件不只可以支持當前的數據類型,同時也能支持將來的數據類型, 這在建立大型系統時爲你提供了十分靈活的功能。 In software engineering, we should not only create well-defined APIs, but also consider reusability. Components can support not only current data types, but also future data types.This provides you with very flexible functionality when creating large systems. 在像C#和Java這樣的語言中,能夠使用泛型來建立可重用的組件,一個組件能夠支持多種類型的數據。 這樣用戶就能夠以本身的數據類型來使用組件。 In languages like C# and Java, generics can be used to create reusable components, and a component can support multiple types of data. This allows users to use components with their own data types.ide
泛型之Generic Generic Generic identity函數。 這個函數會返回任何傳入它的值。 你能夠把這個函數當成是echo命令。 identity Function. This function returns any value passed in. You can think of this function as echo command. 不用泛型的話,這個函數多是下面這樣:函數
Without generics, this function might be as follows: function identity(arg:number):number{ return arg; } function identity(arg:any):any{ return arg;//傳入的類型與返回的類型應該是相同的。 }
咱們須要一種方法使返回值的類型與傳入參數的類型是相同的。 這裏,咱們使用了 類型變量,它是一種特殊的變量,只用於表示類型而不是值。 We need a way to make the type of the return value the same as the type of the incoming parameter. Here, we use a type variable, which is a special variable and is used only to represent a type rather than a value.flex
function identity<T>(arg:T):T{ return arg; }
咱們定義了泛型函數後,能夠用兩種方法使用。 第一種是,傳入全部的參數,包含類型參數: After we define generic functions, we can use them in two ways. The first is to pass in all parameters, including type parameters:this
let output=identity<string>("myString");//string
第二種方法更廣泛。利用了類型推論 -- 即編譯器會根據傳入的參數自動地幫助咱們肯定T的類型: The second method is more common. Using type inference, the compiler automatically helps us determine the type of T based on the parameters passed in: let output=identity("mySomething");//string 使用泛型變量 Using generic variablesspa
function identity<T>(arg:T):T{ return arg; }
若是咱們想同時打印出arg的長度。 咱們極可能會這樣作: If we want to print the length of Arg at the same time. We are likely to do so:prototype
function identity<T>(arg:T[]):T[]{ console.log(arg.length); return arg; } function loggingIdentity<T>(arg:Array<T>):Array<T>{ console.log(arg.length); return arg; }
泛型類型 generic typescode
function identity<T>(arg:T):T{ return arg; } let myIdentity:<T>(arg:T)=>T=identity;
咱們也能夠使用不一樣的泛型參數名,只要在數量上和使用方式上能對應上就能夠。 We can also use different generic parameter names as long as they correspond quantitatively and in terms of usage.component
function identity<T>(arg:T):T{ return arg; } let myIdentity:<U>(arg:U)=>U=identity;
咱們還能夠使用帶有調用簽名的對象字面量來定義泛型函數: We can also use object literals with call signatures to define generic functions:對象
function identity<T>(arg:T):T{ return arg; } let myIdentity:{<T>(arg:T):T}=identity;
這引導咱們去寫第一個泛型接口了。 咱們把上面例子裏的對象字面量拿出來作爲一個接口: This leads us to write the first generic interface. Let's take the literal quantities of the objects in the example above as an interface:接口
interface GenericIdentityFn{ <T>(arg:T):T; } function identity<T>(arg:T):T{ return arg; } let myIdentity:GenericIdentityFn=identity;
一個類似的例子,咱們可能想把泛型參數看成整個接口的一個參數。 這樣咱們就能清楚的知道使用的具體是哪一個泛型類型。 For a similar example, we might want to consider generic parameters as a parameter of the entire interface. In this way, we can clearly know which generic type we are using. 這樣接口裏的其它成員也能知道這個參數的類型了。 So that other members of the interface can also know the type of this parameter.
interface GenericIdentityFn<T>{ (arg:T):T; } function identity<T>(arg:T):T{ return arg; } let myIdentity:GeneratorFunction<number>=identity;//把非泛型函數簽名做爲泛型類型一部分
除了泛型接口,咱們還能夠建立泛型類。 注意,沒法建立泛型枚舉和泛型命名空間。 In addition to generic interfaces, we can also create generic classes. Note that generic enumerations and generic namespaces cannot be created. 泛型類 generic class
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;};
與接口同樣,直接把泛型類型放在類後面,能夠幫助咱們確認類的全部屬性都在使用相同的類型。 Just like interfaces, placing generic types directly behind classes can help us confirm that all attributes of classes use the same type. 泛型約束 Generic constraints
function loggingIdentity<T>(arg:T):T{ console.log(arg.length); return arg; }
咱們定義一個接口來描述約束條件。 建立一個包含 .length屬性的接口,使用這個接口和extends關鍵字還實現約束: We define an interface to describe constraints. Create an interface with. length attributes, and use this interface and extends keywords to implement constraints:
interface Lengthwise{ length:number; } function loggingIdentity<T extends Lengthwise>:T{ console.log(arg.length); return arg; }
在泛型約束中使用類型參數 Using type parameters in generic constraints 你能夠聲明一個類型參數,且它被另外一個類型參數所約束。好比, You can declare a type parameter and it is constrained by another type parameter. For example,
function find<T,U extends Findable>>(n:Text,s:U){ } find(giraffe,myAnimals);
在泛型裏使用類類型 Use class types in generics
function create<T>(c:{new():T;}):T{ return new c(); }
使用原型屬性推斷並約束構造函數與類實例的關係。 Use prototype attributes to infer and constrain the relationship between constructors and class instances.
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;
by泛型這個很差懂啊,感受也很差用啊