在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定具体类型的一种特性,这样可以极大程度的复用代码
在函数中使用泛型
// 只能创建 数字 类型的数组
function createNumberArray(length: number, value: number): number[] {
const arr = Array<number>(length).fill(value);
return arr;
}
// 只能创建 字符串 类型的数组
function createStringArray(length: number, value: string): string[] {
const arr = Array<string>(length).fill(value);
return arr;
}
// 使用泛型:可以创建任意类型的数组
function createArray<T>(length: number, value: T): T[] {
const arr = Array<T>(length).fill(value);
return arr;
}
const res = createArray<string>(3, "foo");
const res1 = createArray<string | boolean>(3, 'hahaha');
const res2 = createArray<string | boolean>(3, true);
在类中使用泛型
class Log<T> {
run(value: T) {
return value;
}
}
// 指定泛型类是 number,则必须是 number 类型
let log1 = new Log<number>();
log1.run(1);
// 未指定类型,则可以是任意类型
let log2 = new Log();
log2.run("1");
泛型与 new
function factory<T>(type: { new(): T }): T {
return new type();
}
class Person { }
let p = factory<Person>(Person);
console.log(p); // Person { }
在接口中使用泛型
// 声明泛型
interface Calculate {
<T>(a: T, b: T): T
}
let sum2: Calculate = function <T>(a: T, b: T): T {
return a;
};
sum2<number>(1, 2);
// 声明泛型在 接口上(类似柯里化)
interface Calculate2<T> {
<U>(a: T, b: T): U
}
let sum3: Calculate2<number> = function <U>(a: number, b: number): U {
return a + b as any;
};
sum3<string>(1, 2);
泛型约束(对泛型的范围进行约束)
// 1.确保 length 属性存在
interface Length {
length: number;
}
// 类型约束:T 必须有 length 属性
function log<T extends Length>(value: T) {
return value;
}
log("1");
log([1]);
log(1); // 类型“number”的参数不能赋给类型“Length”的参数
// 2.检查对象上的键是否存在
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
let tsInfo = { name: "zhangsan", age: 20 }
// 第一种方式获取对象属性
let name = getProperty(tsInfo, 'name');
let habby = getProperty(tsInfo, 'habby');
// Error:类型" habby" 的参数不能赋给类型 "name" | "age" 的参数
// 第二种方式获取对象属性
let varibel = 'name';
let name2 = tsInfo[varibel as keyof typeof tsInfo];
类型别名
type Cart<T> = { list:T[] } | T[];
let c1:Cart<string> = { list: ['1'] };
let c2:Cart<number> = [1, 2, 3];
应用场景案例
// 1.防抖
type FN = (...args: any[]) => any;
export function debounce<T extends FN>(fn: T, limit: number = 300): (...arg: Parameters<T>) => ReturnType<T> {
let timer: any, lastResult: any
return (...args: any[]) => {
clearTimeout(timer);
timer = setTimeout(() => { lastResult = fn(...args) }, limit);
return lastResult; // lastResult 一直是 undefined
}
}
// 测试
const fn = debounce((msg: number) => {
console.log(msg);
return msg;
});
new Array(1000).fill(0).forEach(index => fn(index));
// 2.节流
type FN = (...args: any[]) => any
export function throttle<T extends FN>(fn: T, limit: number = 300): (...args: Parameters<T>) => ReturnType<T> {
let lastResult: any;
let inThtottle: boolean = false;
return (...args: any[]) => {
if (!inThtottle) {
inThtottle = true;
setTimeout(() => { inThtottle = false }, limit);
lastResult = fn(...args);
}
return lastResult; // lastResult 一直是 undefined
}
}
// 测试
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const fn = throttle((msg: string) => console.log('running...', msg));
async function run() {
for (let index = 0; index < 100; index++) {
await wait(100);
fn(index + '');
}
}
run();
接口
上一篇