frontend-interview
frontend-interview copied to clipboard
TS中的泛型是什么应用场景
泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候在指定类型的一种特性
多个类型参数
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
swap([7, "seven"]); // ['seven', 7]
泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
泛型接口
interface Cart<T> {
list: T[];
}
let cart: Cart<{ name: string; price: number }> = {
list: [{ name: "hello", price: 10 }],
};
console.log(cart.list[0].name, cart.list[0].price);
泛型类
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;
}
}
let arr = new MyArray();
arr.add(1);
arr.add(2);
arr.add(3);
let ret = arr.getMax();
console.log(ret);
泛型类型别名
type Cart<T> = { list: T[] } | T[];
let c1: Cart<string> = { list: ["1"] };
let c2: Cart<number> = [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;
}
TS中的泛型是什么应用场景
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
型的语法是 <>
里写类型参数,一般可以用 T
来表示
-
处理函数参数:做到输入和输出的类型统一
function print<T>(arg:T):T { console.log(arg) return arg }
-
泛型约束:在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法,此时可以对泛型进行约束,只允许这个函数传入那些包含
length
属性的变量。使用关键字extends
-
泛型接口:用接口的方式定义一个函数需要符合的形状
-
泛型类、泛型参数的默认类型
泛型体现了一种面向对象的思想
泛型的本质是参数化类型,就是所操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法的创建中,分别成为泛型类,泛型接口、泛型方法。
为什么使用泛型 TypeScript 中不建议使用 any 类型,不能保证类型安全,调试时缺乏完整的信息。
TypeScript可以使用泛型来创建可重用的组件。支持当前数据类型,同时也能支持未来的数据类型。扩展灵活。可以在编译时发现你的类型错误,从而保证了类型安全。
泛型的使用 使用泛型可以创建泛型函数、泛型接口,泛型类
TS中的泛型是什么应用场景?
泛型函数:可以适用于多个类型,同时又能够保证参数类型与返回值的类型一致
// 类型变量T —— T帮助捕获传入的类型
function identity<T>(arg: T): T {
return arg;
}
泛型函数的使用:
传入所有的参数,包含类型参数 let output = identity
泛型变量: 把泛型变量T当做类型的一部分使用,而不是整个类型,增加了灵活性
// 返回元素类型是T的数组
function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length);
return arg;
}
泛型类型:<T> 泛型接口:
interface GenericIdentityFn {
<T>(arg: T): 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; }
泛型
泛型的本质是参数化类型,通俗的讲就是所操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法的创建中,分别成为泛型类,泛型接口、泛型方法。 TypeScript 可以使用泛型来创建可重用的组件。支持当前数据类型,同时也能支持未来的数据类型。扩展灵活。可以在编译时发现你的类型错误,从而保证了类型安全。
function identity<T>(arg:T): T {
console.log(typeof arg)
return arg
}
let output1 = identity<string>('myString')
let output2 = identity<number>(100)
interface GenericIdentityFn<T> {
(arg: T): T
}
function identity<T>(arg: T): T {
return arg
}
let myIdentity: GenericIdentityFn<number> = identity
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;};
console.info(myGenericNumber.add(2,5));
let stringNumberic=new GenericNumber<string>();
stringNumberic.zeroValue='abc';
stringNumberic.add=function(x,y){return `${x}--${y}`};
console.info(stringNumberic.add('张三丰','诸葛亮'));
泛型变量
会根据参数或前面的<>推算出泛型的类型 其声明类型不为 "void" 或 "any" 的函数必须返回值。
function foo<T>(a: T): T {
return a
}
foo<string>(1) // error
泛型类型
类型是 any,string... 这种,泛型类型就是将泛型作为类型,用在赋值的时候
function foo<T>(a: T): T {
return a
}
let a: <T>(a: T) => T = foo
a = 1 // error
a = foo // ok
泛型接口
泛型类型还可以用接口去描述
interface bar{
<T>(a: T): T
}
let a: bar
a = foo // ok
a = 1 // error
上面是将泛型的定义放在了接口里面,还有一种放在接口的写法,这样接口里的其他都可以使用这个泛型。
interface bar<T>{
(a: T): T
}
interface zoo<T> {
a: T,
b: (args: T) => T
}
let c: zoo<string>
c = [1] // error
c = () => 1 // error
c = {
a: '1',
b: (x) => '1'
}
泛型约束
通过 extends 决定泛型可用的属性,确保属性存在
function foo<T>(a: T) {
a.length // error
}
function foo<T extends []>(a: T) {
a.length // ok, 但同时 a 继承了数组的其他属性方法。 a.reverse // ok
}
interface bar {
length: number
}
function foo<T extends bar>(a: T) {
a.length // ok, 但是 a 只有一个 length 属性
}
const obj = { a: 1, b: 2 }
function foo<T, U extends keyof T>(o: T, k: U): T[U] {
return o[k]
}
foo(obj, 'x') // error
泛型类
泛型类和泛型接口类似,通过外面传入类型可以提供内部使用,同时和泛型约束一样的地方在于可以约束内部属性。
class foo<T>{
bar: T
constructor(x: T) {
this.bar = x
}
}
new foo<string>('1')
function create<T extends foo<string>>(ins: new (x: string) => T): T {
return new ins('1')
}
create(foo).bar = '1' // ok
create(foo).bar = 1 // error
泛型是指在定义函数,接口,类的时候,不明确指定参数的类型,而是用一个变量接收,而在使用的时候根据传入值的类型明确参数的类型,这样大大增加了灵活性和可复用性。 应用场景是一些无法明确输入参数类型,但是又需要根据输入参数类型做相应约束的场景。