TS学习笔记(4)
TypeScript 泛型
泛型是什么?
就是在我们不明白类型的时候给我们一个变量 用来代替类型
举例子
function fn(a:number):number
{
return a
}
上面是随便写的一个函数 因为我们知道才选择定义a为number类型 设置返回值为number类型
但是如果我们不知道呢?又或者我们遇到了一个复杂的类型 例如这个函数是一个回调函数 他需要根据不同的参数值返回不同的结果呢?
这样给他定死显然是不对的 虽然也有别的方法可以解决上面的问题 比如使用 xxx | xxx
还有一种方式是使用 any 这种“万能语法”,果你使用 any 的话,怎么写都是 ok 的, 这就丧失了类型检查的效果等等
但是TS给了一个新的解决方案 那就是泛型,不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能
设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:类的实例成员、类的方法、函数参数和函数返回值。
使用示例
function fn<T>(a:T): T{
return a
}
如何调用呢 有两种方法
fn(10)//不指定泛型,TS可以自动对类型进行判断
let result2 = fn<string>('hello')//指定泛型
当然 不止可以定义一个参数 可以指定两个
function fn2<T,K>(a:T,b:K):T
{
console.log(b);
return a
}
fn2<number,string>(123,'Hello')
接下来才是重要的 之前我们讲了接口
接口的作用是什么?限制!
同样的 泛型也会这样 我们可以让泛型成为继承接口成为其子类
为什么需要做这个呢?
举个例子
function fn4<T>(a:T):T
{
console.log(a.length);
}
报错的原因在于 T 理论上是可以是任何类型的,不同于 any,你不管使用它的什么属性或者方法都会报错(除非这个属性和方法是所有集合共有的)。那么直观的想法是限定传给 trace 函数的参数类型应该有 length类型,这样就不会报错了
所以就需要使用到类型约束 这里使用的就是接口
如何去表达这个类型约束的点呢?实现这个需求的关键在于使用类型约束。 使用 extends 关键字可以做到这一点。简单来说就是你定义一个类型,然后让 T 实现这个接口即可。
interface Inter{
length:number
}
function fn3<T extends Inter>(a:T):number
{
return a.length
}
fn3('123')
fn3(123) //报错
对类进行使用
class MyClass<T>
{
name:T
constructor(name:T)
{
this.name = name
}
}
const mc = new MyClass<string>('孙悟空')
TS的操作符
typeof
interface Person {
name: string;
age: number;
}
const sem: Person = { name: "semlinker", age: 30 };
type Sem = typeof sem; // type Sem = Person
const adc : Sem = {name:'abc',age:5}
在上面代码中,我们通过 typeof 操作符获取 sem 变量的类型并赋值给 Sem 类型变量,之后我们就可以使用 Sem 类型
除了获取对象 还可以获取函数
function toArray(x: number): Array<number> {
return [x];
}
type Func = typeof toArray; // -> (x: number) => number[]
let a = toArray(123)
console.log(a); //[123]
keyof
keyof 操作符是在 TypeScript 2.1 版本引入的,该操作符可以用于获取某种类型的所有键,其返回类型是联合类型
interface Person {
name: string;
age: number;
}
type K1 = keyof Person; // "name" | "age"
type K3 = keyof { [x: string]: Person }; // string | number
keyof 如何使用呢?
我们用一个最简单的prop函数示例
function prop(obj: object, key: string) {
return obj[key];
} //报错
这个函数的作用只是通过传入一个对象 并且传入键如何输出值即可
但是这里却报错
回答的很明确元素隐式地拥有 any 类型,因为 string 类型不能被用于索引 {} 类型。
其实简单来说就是你不能保证 string给定的健你对象一定就是绝地拥有的 不能被保证的 因此我们需要去改
这里就用到了keyof操作符
通过keyof操作符我们把key完全限制起来
function prop<T extends object, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
在以上代码中,我们使用了 TypeScript 的泛型和泛型约束。首先定义了 T 类型并使用 extends 关键字约束该类型必须是 object 类型的子类型,然后使用 keyof 操作符获取 T 类型的所有键,其返回类型是联合类型,最后利用 extends 关键字约束 K 类型必须为 keyof T 联合类型的子类型。
我们实际测试一下
type Todo = {
id: number;
text: string;
done: boolean;
}
const todo: Todo = {
id: 1,
text: "Learn TypeScript keyof",
done: false
}
function prop<T extends object, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const id = prop(todo, "id"); // const id: number
const text = prop(todo, "text"); // const text: string
const done = prop(todo, "done"); // const done: boolean
console.log(id); //1
console.log(text); //Learn TypeScript keyof
console.log(done); //false
const date = prop(todo, "date"); //类型“"date"”的参数不能赋给类型“keyof Todo”的参数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程