# 一、TS 模块化
在 typescript 中主要使用的 ✨ 模块化方法是 ES Module:
export default A
-import A from './A.js'
# 1、TS 模块
在 typescript 中,任何没有 export 或 顶级的 JavaScript 文件 await 都应被视为脚本而不是模块。也就是官网中的Non-modules (opens new window)。
但如果我们没有任何 import
或者 export
时,我们仍然希望它作为模块处理,我们可以添加:
export {}
关于 typescript 模块导入,也有一些注意事项:
在 Typescript 4.5 开始,我们可以使用 type 前缀,来表明被导入的是一个类型
类型导入
- utils / math.ts
export interface IPerson {
name: string
age: number
}
export type IDType = number | string
- index.ts
import type { IPerson, IDType } from './utils/type'
// import { type IPerson, type IDType } from './utils/type'
# 2、命名空间
先看一个问题:
export function format(price) {
return '¥' + price
}
// 下面代码报错
export function format(dateString) {
return '2022-10-10'
}
方案 1
export function formatPrice(price) {
return '¥' + price
}
export function formatDate(dateString) {
return '2022-10-10'
}
在早期,typescript 中是可以使用命名空间 namespace(内部模块) 来解决这个问题:
提示
虽然 ts 命名空间还没有被弃用,但是 ES 模块已拥有命名空间的大部分特性,因此更加推荐使用 ES 模块(跟随时代发展,虽然一些旧的库中是存在使用命名空间的情况)
方案 2
// 模块化 + 命名空间
export namespace price {
export function format(price) {
return '¥' + price
}
}
export namespace date {
export function format(dateString) {
return '2022-10-10'
}
}
// 使用
import { price } from '..'
// price.format
# 二、声明文件.d.ts
# 类型声明
除了.ts 文件外,还有.d.ts
文件 —— 用来只做类型声明(类型定义 Type Definition)的文件。
那什么情况下需要使用.d.ts 文件呢?
编写第三方库的类型信息(当然,有的库是支持 ts 的,已经写好了.d.ts 文件)
根据需求提前声明一些全局性质的类型
├── types
├── index.ts
├── login.d.ts
├── AMap.d.ts
└── others.d.ts
# 1、内置
const imgElm = document.querySelector('.pic') as HTMLImageElement
关于 typescript 环境默认自带了哪些内置类型声明,详细可以查看:
https://github.com/microsoft/TypeScript/blob/main/src/lib/README.md
具体包含的 API 集有:
- ECMAScript 语言特性 - 例如 JavaScript API,如 Array 上的函数、Promise 等
- DOM API - 例如 Web 浏览器中可用的 API,比如 Window、Document 等
- ……
# 2、第三方
关于我们使用的一些库,通常会有两种形式出现:
提示
其实在最新的 npmjs.com 官网搜索 npm 包是,我们发现包的会有一个后缀:
- TS(表示当前包已经编写了.d.ts 文件)
- DT(提示当前包存在可下载的类型声明的包)
- 方式 1:npm 后可以发现其库中已经进行了类型声明(编写了.d.ts 文件)
import type { AxiosRequestConfig, AxiosInstance } from 'axios'
axios.createInstance(config: AxiosRequestConfig)
- 方式 2:有些库没有进行类型声明时,我们可以使用公共库DefinitelyTyped (opens new window)
npm install lodash
npm i @types/lodash
# 3、自定义(declare)
declare module 和 declare namespace 的区别
官方描述:Namespaces (opens new window)、Namespaces and Modules (opens new window)
在 TypeScript 1.5 中,命名法已更改。“内部模块”现在是“命名空间”。“外部模块”现在只是“模块”,以符合 ECMAScript 2015 的术语。即 module X (相当于现在首选 namespace X )。
// (外部)模块
declare module "buffer"
// 内部模块 -> 命名空间
declare module NodeJS // 以前
declare namespace NodeJS // 现在
# ① declare 模块
下面我们以高德地图的 JS API 为例:
- types / AMap.d.ts
declare module 'AMap'
// 或者
declare module 'AMap' {
export plugin(name: string | Array<any>, callback: Function): void;
}
# ② declare 文件 ✍
常见的,我们在全局中还会声明一些文件模块(下面以 vite 创建的项目为例):
在真实的脚手架项目中,对文件模块的声明往往不需要我们手动 declare 的
声明文件模块
类似的声明,在 env.d.ts 中已经集成 /// <reference types="vite/client" />
vite 描述:client-types (opens new window)
- types / Imgs.d.ts
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.svg'
declare module '*.jpg' {
const src: string
export default src
}
关于 vue 文件的声明,在 .vscode/extensions.json 已经提示了可以安装的插件来进行辅助开发。
其中 Vue.vscode-typescript-vue-plugin (opens new window) 可以帮助我们读取未进行类型声明的.vue 文件,因此不对.vue 文件进行类型声明也可以。
// 如果安装了上述插件,不写下面文件声明也是可以的
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent
export default component
}
# ③ declare 命名空间
除了上面的几种情况,我们还可以会遇到引入 SDK 的情况,以 QQ 互联的 js JDK 为例:
- 没有 import
<!-- QQ 互联 -->
<script
src="http://connect.qq.com/qc_jssdk.js"
data-appid="100556005"
data-redirecturi="http://www.corho.com:8080/#/login/callback"
></script>
<!-- jQuery -->
<script src="https://unpkg.com/[email protected]/dist/jquery.js"></script>
- types / index.d.ts
// 声明命名空间
declare namespace QC {
export function init(appId: string, callback?: () => void): void
export function login(params: any): void
// 其他函数和对象的声明...
}
declare namespace $ {
export function ajax(setting: any): any
}
开发应用
declare module 'three'
declare module '@/components/waves.vue'
declare interface Window {
_AMapSecurityConfig: any
}
declare let $: JQuery
export default $
import 'pinia'
import type IMCore from '@/stores/plugin/IM-plugin/IM-core'
declare module 'pinia' {
// store 中添加新的属性
export interface PiniaCustomProperties {
// IM核心功能
timCore: IMCore
}
}
# 三、tsconfig.json
官方手册:
注意
在开发中,我们更多的是使用 webpack 中的 ts-loader 进行打包时自动读取 tsconfig 文件,并根据配置来编译 Typescript 代码。
并且更多时候,无论我们使用 Vue Cli 还是 Vite 创建项目时,选择了 Typescript 模板后,tsconfig 文件会默认帮我们配置好的。
# 顶层选项
{
"compilerOptions": {
//
},
"files": [], // 指定哪些ts文件需要进行编译
"include": ["./src/**/*.ts", "./types/*.d.ts"], // 指定要编译哪些ts文件
"exclude": ["node_modules"] // 指定要从includes中排除哪些文件
// 其他
}
# 1、默认配置
在 TypeScript 中,当将 strict 编译选项设置为 true 时,默认情况下不允许使用 any 类型,因为 any 类型相当于关闭了 TypeScript 对类型的检查,这与 strict 模式的目的相违背。
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
// "noImplicitAny": true, /* ts编辑器无法推断变量类型,是否禁止🤔隐式 any 类型 */
// "strictNullChecks": true, /* 是否对可能为'null'和'undefined'的值进行检查 */
"skipLibCheck": true
}
}
去官网,查阅一下,当"strict": true
时,它包含了哪些配置?
答案
略
# 2、strict 模式 🎈
关于"strict": true
的体现(只选了常见的记录一下):
"noImplicitAny": true
提示
默认情况下,采用的是不允许存在 隐式 any 类型。开发中,可根据需要将其改为 false。
// 参数bar有警告
function foo(bar) {
console.log(bar)
}
"strictNullChecks": true
提示
如果需要处理可能为 null
或 undefined
的变量,则可以使用可选链操作符 ?
或非空断言操作符 !
进行处理。同理,开发中,可根据需要将其改为 false。
// 情况1
let str: string = null // 报错
// 情况2 🤔
let obj: { prop: string } | null = null
obj.prop // 报错 ---》 解决办法(可选链操作符):obj?.prop
// 情况3 🤔
let str: string | null = null
function foo(str: string) {
console.log(str.length)
}
foo(str) // 报错 ---》 解决办法(非空断言操作符):foo(str!)
# 3、个性化配置
{
"compilerOptions": {
"rootDir": "./src", // 对指定目录文件进行编译(默认./)
// "rootDir": "./",
// "rootDirs": [],
"outDir": "./dist" // 指定编译生成.js文件放置位置(默认./)
// "outDir": "./",
}
}
# 4、自动生成
# 1、生成tsconfig.json
tsc --init
默认配置:
← 内置工具 【axios请求封装✨】 →