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”的参数
posted @   jeffmmo  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示