TypeScript 模块那些事儿

哈喽,大家好,我是 SuperYing。今天我们来聊聊 TypeScript 模块那些事儿。

关于术语的一点说明:
TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”,这是为了与 ECMAScript 2015 里的术语保持一致,(也就是说 module X { 相当于现在推荐的写法 namespace X {)。

什么是模块

TypeScript 沿用了 ES6 的模块概念。模块只能在其自身的作用域内执行,而不是在全局作用域里。模块内的变量,函数,类等可以通过 export 导出,也可以通过 import 导入所需的其他模块内容。
模块更形象的叫法应该是“文件模块”,任何包含 import 或 export 的文件,都会被识别为模块。相反,若一个文件中没有 importexport,则该文件内容全局可见。

用法

  • 导出
    • 导出声明
    // 导出变量
    export const foo = '123'
    // 导出类型
    export type FooType = {
        foo: string
    }
    // 导出函数
    export function bar() {
        console.log(123)
    }
    
    • 导出语句
    // 导出变量
    const foo = '123'
    // 导出类型
    type FooType = {
        foo: string
    }
    // 导出函数
    function bar() {
        console.log(123)
    }
    export { foo, FooType, bar }
    
    • 重新导出,可以通过 as 重命名变量并导出
    const foo = '123'
    export { foo as renamedFoo }
    
    • 默认导出
      每个模块仅能有一个默认导出,使用 default 关键字标记。
    export default '123'
    export default function Foo() {}
    export default class Foo {}
    
  • 导入
    • 导入模块的一个变量或类型
    import { foo } from './foo'
    
    • 重命名导入的变量或类型
    import { foo as renamedFoo } from './foo'
    
    • 导入整个模块,使用 * as 指定一个对象,导入模块的所有输出值都赋值给该对象
    import * as Foo from './foo'
    
    • 只导入模块,有些模块内部可能会设置某些全局状态,供其他模块使用,在模块没有任何导出或者用户不关心其导出内容时,可以使用如下方式导入:
    import 'core-js'; // 一个普通的 polyfill 库
    
    • 默认导入
    import defaultFoo from './foo'
    

查找策略

模块查找策略相关的 TypeScript 配置:
开启 moduleResolution: node 选项,启用 Node 模式;如果使用了 module: commonjsmoduleResolution: node 会默认开启。

模块查找场景主要分为以下两种:

  • 相对路径模块(以 . 开头,例如 ./foo, …/foo 等)
  • 其他动态查找模块(如 vue, react, reactDOM 等)

相对路径模块

仅按照相对路径规则查找即可:

  • 如果文件 bar.ts 中含有 import * as foo from './foo',那么 foo 文件必须与 bar.ts 文件存在于相同的文件夹下。
  • 如果文件 bar.ts 中含有 import * as foo from '../foo',那么 foo 文件所存在的地方必须是 bar.ts 的上一级目录。
  • 如果文件 bar.ts 中含有 import * as foo from '../someFolder/foo',那么 foo 文件所在的文件夹 someFolder 必须与 bar.ts 文件所在文件夹在相同的目录下。

其他动态查找模块

若导入路径不是相对路径,则模块查找与 Node 模块解析策略相似。

  • 当你使用 import * as foo from 'foo',将会按如下顺序查找:

    • ./node_modules/foo
    • ../node_modules/foo
    • ../../node_modules/foo
    • 直到系统的根目录
  • 当你使用 import * as foo from 'something/foo',将会按照如下顺序查找:

    • ./node_modules/something/foo
    • ../node_modules/something/foo
    • ../../node_modules/something/foo
    • 直到系统的根目录

导入模块解析

仍然以 import * as foo from 'foo' 为例:

  • 若 foo 是一个文件,匹配。
  • 否则,若 foo 是一个文件夹,且存在 foo/index.ts, 匹配。
  • 否则,若 foo 是一个文件夹,且存在 package.json 文件,在该文件中指定了 types 属性且对应的文件存在,匹配。
  • 否则,若 foo 是一个文件夹,且存在 package.json 文件,在该文件中指定了 main 属性且对应的文件存在,匹配。

模块编译

通过设置 tsconfig 编译选项 module 的值,可以把 TavaScript 模块编译成不同 JavsScript 模块类型。

  • "CommonJS":NodeJs 模块。
  • "AMD":Require.js 模块。
  • "System":SystemJs 模块。
  • "UMD":兼容多个模块加载器,或者不使用模块加载器(全局变量)。
  • "ES6""ES2015":ES6 模块。
    目前比较常用的是 CommonJSUMDES6,大部分框架或库会同时编译为这三种模式,如 Element-Plus。

*.d.ts

我们在使用 TypeScript 开发的时候,有时会用到非 TypeScript 类库,它们没有自己的类型,我们在引入的时候,往往会收到 TypeScript 的报错信息,类似于 ‘无法解析对应的模块’
那么如何搞定这种类库的类型呢,这时候就需要我们来手动声明类库暴露出来的 API 了。这类声明通常在 .d.ts 文件中定义。(这里使用 module 关键字,并且名称使用引号包裹)

declare module "url" {
    export interface Url {
        protocol?: string;
        hostname?: string;
        pathname?: string;
    }

    export function parse(urlStr: string, parseQueryString?, slashesDenoteHost?): Url;
}

有时候我们只是想快速使用某个类库模块,并不想去一一声明其 API 类型。可以使用如下简写形式

declare module "url"

简写形式下所有导出的类型都是 any

好啦!以上便是「 TypeScript 模块 」的全部内容,感谢阅读。

欢迎各路大佬讨论、批评、指正,共同进步才是硬道理!

### 在 VSCode 中实现 React 前端与 Spring Boot 后端的集成 #### 一、环境准备 为了完成 React 和 Spring Boot 的集成,需要先配置好开发环境。以下是必要的工具和技术栈: - **IDE**: 使用 Visual Studio Code (VSCode) 进行开发。 - **前端技术栈**: React.js 及其生态组件库。 - **后端技术栈**: Spring Boot 框架用于构建 RESTful API。 - **通信协议**: HTTP/HTTPS 协议作为前后端交互的基础。 确保已安装 Node.js 和 Java Development Kit (JDK),并设置 Gradle 或 Maven 来管理依赖项[^2]。 --- #### 二、项目结构设计 通常情况下,可以采用两种方式组织代码: 1. 将 React 应用嵌入到 Spring Boot 工程中; 2. 分离部署模式——即分别运行两个独立的服务并通过代理机制进行跨域请求处理。 对于初学者来说推荐第二种方法因为它更灵活也更容易维护。 --- #### 三、具体实施步骤说明如下 ##### (一)创建 Spring Boot 服务端程序 利用 Spring Initializr 初始化一个新的 Spring Boot 项目,并添加 Web Starter Library 支持REST APIs 功能模块。接着定义一些简单的 Controller 类用来响应来自客户端的数据查询操作比如获取用户列表之类的业务逻辑功能接口示例代码片段展示如下所示: ```java @RestController @RequestMapping("/api/users") public class UserController { @GetMapping public List<String> getAllUsers() { return Arrays.asList("Alice", "Bob"); } } ``` 上述例子展示了如何暴露 `/api/users` 路径下的 GET 请求处理器返回模拟数据集合给调用方知道即可[^1]. --- ##### (二)搭建 React 客户端应用程序 打开终端命令窗口执行 `npx create-react-app my-front-end --template typescript`, 创建基于 TypeScript 版本的新建空白模板工程文件夹命名为my-front-end. 进入该目录之后修改 package.json 文件内的 scripts 字段新增 start-proxy 参数指向本地服务器监听地址 port number 设置为3000 默认值不变最后保存退出编辑器继续往下看下一步骤内容描述部分吧! --- ##### (三)解决 CORS 问题 由于浏览器的安全策略限制,默认不允许不同域名之间的资源互相访问(除非明确允许),所以我们得想办法绕过这个障碍才行啊!一种常见的做法就是在 Express Server 上面启用 cors middleware 插件来动态调整 Access-Control-Allow-Origin 头部字段从而达到目的效果啦~下面是具体的解决方案演示过程截图分享给大家参考学习哦~ 在 main application entry point file inside backend source code add these lines of codes at very beginning before any route definitions happen please remember to install npm packages first by running command 'npm i express cors' then require them accordingly as shown below : ```javascript const express = require('express'); const cors = require('cors'); const app = express(); app.use(cors()); // rest of your routes go here... ``` 这样就可以让所有的外部来源都能够顺利地发起 AJAX calls 到我们的 api endpoints 啦!不过出于安全性考虑建议只针对特定白名单范围开放权限比较好一点哈😊 另外还有一种更加优雅的办法就是借助于 webpack dev server 提供的功能选项 configureProxy 属性来进行转发设定同样也能有效规避掉此类麻烦事儿呢😏详情可查阅官方文档了解更多细节哟! --- ##### (四)测试联调结果验证正确性与否? 当以上各项工作都顺利完成以后便可以尝试启动各自的服务进程观察实际表现情况是否符合预期目标要求咯😄记得要按照正确的顺序依次开启噢~先是后台紧接着才是前台不然可能会因为找不到对应的 handler 导致报错异常现象发生哒😎 --- ### 总结陈词 综上所述我们已经成功实现了在一个现代化 IDE 平台上将流行的 JavaScript 框架同主流企业级 java 微服务体系相结合起来形成了一套完整的全栈式 web 解决方案模型可供大家借鉴模仿实践运用至自己的真实工作场景当中去发挥更大价值创造更多可能未来展望无限美好期待共同进步成长💪✨
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端嘟老板

何其有幸,得君支持,万分感谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值