TS泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,
而在使用的时候再指定类型的一种特性
使用场景 入参和返回值的类型有映射关系
泛型函数
// 泛型简单使用
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result = createArray2<string>(3,'x');
console.log(result);
泛型type
type Cart<T> = {list:T[]} | T[];
let c1:Cart<string> = {list:['1']};
let c2:Cart<number> = [1];
两种使用方法
// 1) 使用接口的时候确定的类型
type ICallback<T> = (item: T, idx: number) => void;
// 2) 在调用函数的时候确定了类型
type IForEach = <T>(arr: T[], callback: ICallback<T>) => void;
// type ICallback1 = <T>(item: T, idx: number) => void;
const forEach: IForEach = (arr, callback) => {
for (let i = 0; i < arr.length; i++) {
callback(arr[i], i); // callback 没有执行, 所以无法推导arr[i] = T
}
};
forEach(["a", "b", "c", 1], function (item) {
console.log(item);
});
泛型接口
约束 变量的值 为 一个泛型函数
(须变量使用时赋值T,因为 使用该变量 就相当于 使用 泛型函数)
interface Calculate{
<T>(a:T,b:T):T
}
let add:Calculate = function<T>(a:T,b:T){
return a;
}
add<number>(1,2);
注意上下两个例子<T>
的位置,以及<T>
的赋值时机
约束 变量的值 为 一个与T相关的函数
(须接口使用时赋值T)
interface Calculate<T>{
(a:T,b:T):T
}
let add:Calculate<number> = function(a:number,b:number):number{
return a;
}
add(1,2);
泛型类
class MyArray<T>{
private list:T[]=[];
add(value:T) {
this.list.push(value);
}
getMax():T {
let result=this.list[0];
for (let i=0;i<this.list.length;i++){
if (this.list[i]>result) {
result=this.list[i];
}
}
return result;
}
}
使用时传入factory
function factory<T>(type: {new():T}): T {
return new type(); // This expression is not constructable.
}
class Person {}
let p = factory<Person>(Person)
console.log(p)
传入多个泛型
function swap<A,B>(tuple:[A,B]):[B,A]{
return [tuple[1],tuple[0]];
}
let swapped = swap<string,number>(['a',1]);
console.log(swapped);
console.log(swapped[0].toFixed(2));
console.log(swapped[1].length);
泛型默认值
function createArray3<T=number>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result2 = createArray3(3,'x');
console.log(result2);
泛型约束
只要含有约束的属性就行,可以有额外的属性(或者说范围比约束的还小)
interface LengthWise {
length: number
}
//可以让泛型继承一个接口
function logger2<T extends LengthWise>(val: T) {
console.log(val.length)
}
logger2('lzy');
logger2(1);
约束 传入的泛型 为 string 或 string[]
// 这里只能用type 不能用 interface,
// 因为interface无法表示这种类型,只能表示class或function或object
type LengthWise = string|string[]
function logger2<T extends LengthWise>(val: T) {
console.log(val.length)
}
extends 联合类型,调用时传入变量的类型,必须小于或等于联合类型(范围更小)
普通type,调用时传入变量的类型,属性必须多于或等于type(范围更小)
function getVal<T extends object, U extends keyof T>(obj: T, key: U) {
return obj[key];
}
getVal({ a: 1, b: 2, c: 3 }, "c");
compose
type Func<T extends any[], R> = (...a: T) => R
/**
* Composes single-argument functions from right to left. The rightmost
* function can take multiple arguments as it provides the signature for the
* resulting composite function.
*
* @param funcs The functions to compose.
* @returns A function obtained by composing the argument functions from right
* to left. For example, `compose(f, g, h)` is identical to doing
* `(...args) => f(g(h(...args)))`.
*/
export default function compose(): <R>(a: R) => R
export default function compose<F extends Function>(f: F): F
/* two functions */
export default function compose<A, T extends any[], R>(
f1: (a: A) => R,
f2: Func<T, A>
): Func<T, R>
/* three functions */
export default function compose<A, B, T extends any[], R>(
f1: (b: B) => R,
f2: (a: A) => B,
f3: Func<T, A>
): Func<T, R>
/* four functions */
export default function compose<A, B, C, T extends any[], R>(
f1: (c: C) => R,
f2: (b: B) => C,
f3: (a: A) => B,
f4: Func<T, A>
): Func<T, R>
/* rest */
export default function compose<R>(
f1: (a: any) => R,
...funcs: Function[]
): (...args: any[]) => R
export default function compose<R>(...funcs: Function[]): (...args: any[]) => R
export default function compose(...funcs: Function[]) {
if (funcs.length === 0) {
// infer the argument type so it is usable in inference down the line
return <T>(arg: T) => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args: any) => a(b(...args)))
}