首页 前端知识 TypeScript系列:泛型、模块—浅析

TypeScript系列:泛型、模块—浅析

2024-06-09 09:06:34 前端知识 前端哥 27 98 我要收藏

目录

基础说明

泛型类型

泛型接口

泛型类

泛型约束

模块

导出

导出声明

导出语句

重新导出

导入

导入一个模块中的某个导出内容

将整个模块导入到一个变量,并通过它来访问模块的导出部分

默认导出&导入


        TypeScript 是由微软开发的一款开源的编程语言,TypeScript 是 Javascript 的超集,遵循最新的 ES6、ES5 规范,TypeScript 扩展了 JavaScript 的语法。TypeScript 更像后端 Java、C#这样的面向对象语言,可以让 JavaScript 开发大型企业项目。谷歌也在大力支持 Typescript 的推广,谷歌的 angular2.x+ 就是基于 Typescript 语法,最新的 Vue 、React 也可以集成 TypeScript。Nodejs 框架中的 Nestjs、midway 中用的就是 TypeScript 语法。

基础说明

如果我们需要定义一个函数,一个入参和一个返回值,入参和返回值类型需要保持一致,怎么办?

比如规定类型都是字符串,那么:

function doit(arg: string): string {
    return arg;
}

可以看出来,类型这里写死成string了,那类型可不可以像参数一样定义成变量传递进来?当然可以,我们改造一下代码:

function doit<T>(arg: T): T {
    return arg;
}

这里通过<T>定义了一个类型变量T,而这个T具体是什么类型,使用的时候用户传递即可:

let result: string = doit<string>("我是一个字符串");

事实上,编译器通过查看arg的值的类型,可以推断出T表示什么类型,因此,大部分情况下,上述代码可以简化一下:

let result: string = doit("我是一个字符串");

泛型类型

function doit<T>(arg: T): T {
    return arg;
}
 
let myDoit: Function = doit;

我们想把函数doit赋值给变量myDoit,我们定义myDoit的类型是Function,那么,可不可以明确一下myDoit的类型细节?答案是肯定的:

let myDoit: <T>(arg: T) => T = doit;

let myDoit: { <T>(arg: T): T } = doit;

泛型接口

聪明的是肯定可以想到,我们还可以定义一个接口:

interface DoitFnType {
    <T>(arg: T): T;
}
    
let myDoit: DoitFnType = doit;

类型锁定

现在有一个情况,我们在给myDoit赋值的是,已经明确了类型T的实际值一定是string,那么,就可以这样改动:

interface DoitFnType<T> {
    (arg: T): T;
}
    
let myDoit: DoitFnType<string> = doit;

泛型类

也非常简单,我们直接举个例子:

class Dog<T>{
    info: T;
    setInfo(info: T): void {
        this.info = info;
    }
}

创建的时候也是类似的:

let dog = new Dog<string>();

那么,setInfo函数就只能传递字符串类型:

dog.setInfo('小狗🐶');

而下面的写法就是错误的:

// Argument of type 'boolean' is not assignable to parameter of type 'string'.    
dog.setInfo(true);

温馨提示:类的静态属性不能使用这个泛型类型,为什么?因为类型值是new的时候设置的,静态的时候根本不存在。

泛型约束

function doit<T>(arg: T) {
 
    // Property 'length' does not exist on type 'T'.
    console.log(arg.length);
}

在上面的代码中,我们希望打印arg的属性length,虽然类型T待定,可是我们明确知道传递的数据一定会有length属性。可是,编译器并不能证明类型T包含lenght属性,因此会提示错误。

怎么办?我们把代码改造一下:

interface ArgType {
    length: number;
}
 
function doit<T extends ArgType>(arg: T) {
    console.log(arg.length);
}

现在这个泛型被约束了,传递的参数必须包含length属性,比如字符串是可以的:

doit("小花");

而数字就不行:

// Argument of type 'number' is not assignable to parameter of type 'ArgType'.
doit(10);

模块

导出

导出声明

比如变量、函数、类、类型别名或接口等,例如:

export interface DemoType { }

或者

export const demo: number = 10;

当然,别的声明也可以,这里就不一一举例子了。如何记住?在声明语句的开头加一个export即可。

导出语句

有时候,我们可能需要先声明,然后导出,可以使用类似下面的语句:

class DemoClass {}
 
// 导出
export { DemoClass };

当然,导出的时候,可以修改名称:

export { DemoClass as ExampleClass };

重新导出

比如我们导出一个功能来自一个已经存在的模块:

export { demoFun } from "./demo";

或者一个模块可以包裹多个模块,并通过下面的语法把他们导出的内容联合在一起:

export * from "demo";

导入

导入一个模块中的某个导出内容

import { demoFun } from "./demo";

可以对导入内容重命名

当然,导出的内容可以改名后使用:

import { demoFun as doit } from "./demo";

将整个模块导入到一个变量,并通过它来访问模块的导出部分

比如我们把demo模块导出成一个变量demo:

import * as demo from "./demo";

那么,本来的demoFun就可以这样访问:

demo.demoFun();

默认导出&导入

导出的时候,只需要把export改成export default即可,例如:

export default function() { }

导入的时候,用一个变量(合理的标志符即可)接一下就可以了:

import demoFun from "./demo";

转载请注明出处或者链接地址:https://www.qianduange.cn//article/11660.html
标签
评论
发布的文章
大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!