泛型就是在不知道什么类型的时候,用一个变量来暂时替代,以保证后续的类型的一致性
使用泛型
使用方法是在类的声明的时候,用
class Queue<T> {queue: T[] = [];constructor(arr: T[]) {this.queue = arr;}push(item: T) {this.queue.push(item);}shift() {this.queue.shift();}}let queue = new Queue(["1", "2", "3"]);console.log(queue);//Queue { queue: [ '1', '2', '3' ] }queue.push("4");console.log(queue);//Queue { queue: [ '1', '2', '3', '4' ] }queue.push(5);//错误
//接口interface userAction<T> {canWalk: T;walk(param: T): T;}let a: userAction<string> = {canWalk: "true",walk(param) {return param;}};console.log(a.walk("walking"));
泛型组成的类型
function addOne<T>(arr: T[], item: T): Array<T> {let ARR = arr;ARR.push(item);return ARR;}console.log(addOne<number>([1, 2, 3], 1));console.log(addOne(["1", " 2", " 3"], " 1"));console.log(addOne<number>([1, 2, 3], '1'));//报错console.log(addOne<number>(["1", " 2", " 3"], " 1"));//报错
使用了泛型后加不加类型都可以,不加的话就可以写任何类型,保证类型一致即可,但是加上的话就只能写限定的类型了
泛型的默认值
泛型可以像函数参数一样用等号设定默认值,在没有设置具体类型以及无法推断类型的时候会起作用
function createArray<T = string>(length: number, value: T): Array<T> {let result: T[] = [];for (let i = 0; i < length; i++) {result[i] = value;}return result;}
泛型的继承
泛型可以有多个参数,而且泛型也可以有继承关系
function copyFields<T extends U, U>(target: T, source: U): T {for (let id in source) {target[id] = (<T>source)[id];}return target;}let x = { a: 1, b: 2, c: 3, d: 4 };copyFields(x, { b: 10, d: 20 });
泛型约束
有时候我们需要输出一个变量的length,比如数组、string以及我们自定义的一个带有length属性的变量,这时我们就需要用到泛型约束了
interface hasLength {length: number;}function logLength<T extends hasLength>(param: T) {console.log(param.length);}logLength('111111')logLength([1,2,3,4])logLength({length:10})
取对象的值
另外我们有时候需要使用某个对象中的一些属性,但是我们我们不能保证这个属性在对象上,这个时候可以使用泛型约束以及keyof操作符
keyof操作符用来获取键的种类,有自定义的时候就会返回具体的键,没有的时候就会返回键的类型
interface Person {name: string;age: number;location: string;}type K1 = keyof Person; // "name" | "age" | "location"type K2 = keyof Person[]; // number | "length" | "push" | "concat" | ...type K3 = keyof { [x: string]: Person }; // string | number
需要注意,在有自定义的键的时候会返回键名的字面量类型组成的联合类型,如下
interface User {name: string;age: number;}type keys = keyof User//'name'|'age'let a: keys = "name";let b: keys = "names";//错误,因为只能赋值'name'或者'age'
function logValue<T, U>(param: T, key: U): void {console.log(param[key]);}//报错Type 'U' cannot be used to index type 'T'function logValue<T, U extends keyof T>(param: T, key: U): void {console.log(param[key]);}//通过
因为keyof得到了对象的键,因此要取得对象的键值就不会报错。
