本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《
阿里云开发者社区用户服务协议
》和
《
阿里云开发者社区知识产权保护指引
》。如果您发现本社区中有涉嫌抄袭的内容,填写
侵权投诉表单
进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
1.1 声明文件
什么是声明文件?
声明文件就是给
js
代码补充类型标注. 这样在
ts
编译环境下就不会提示
js
文件"缺少类型".
声明变量使用关键字
declare
来表示声明其后面的全局变量的类型, 比如:
// packages/global.d.ts
declare var __DEV__: boolean
declare var __TEST__: boolean
declare var __BROWSER__: boolean
declare var __RUNTIME_COMPILE__: boolean
declare var __COMMIT__: string
declare var __VERSION__: string
上面代码表示
__DEV__
等变量是全局, 并且标注了他们的类型. 这样无论在项目中的哪个
ts
文件中使用
__DEV__
, 变量
ts
编译器都会知道他是
boolean
类型.
声明文件在哪里?
声明文件的文件名是有规范要求的, 必须以
.d.ts
结尾。声明文件放在项目里的任意路径/文件名都可以被
ts
编译器识别, 但实际开发中发现, 为了规避一些奇怪的问题, 推荐放在根目录下.
声明文件对纯js项目有什么帮助?
即便你只写
js
代码, 也可以安装声明文件, 因为如果你用的是
vscode
, 那么他会自动分析
js
代码, 如果存在对应的声明文件,
vscode
会把声明文件的内容作为代码提示。
1.2. @types和DefinitelyTyped仓库
DefinitelyTyped
是一个高质量的
TypeScript
类型定义的仓库。通过
@types
方式来安装常见的第三方JavaScript库的声明适配模块
1.3. lib.d.ts
当你安装
TypeScript
时,会顺带安装
lib.d.ts
等声明文件。此文件包含了
JavaScript
运行时以及
DOM
中存在各种常见的环境声明。
它自动包含在 TypeScript 项目的编译上下文中;
它能让你快速开始书写经过类型检查的 JavaScript 代码。
你可以通过指定
—noLib
的编译器命令行标志(或者在 tsconfig.json 中指定选项 noLib: true)从上下文中排除此文件。
看如下例子
const foo = 123;
const bar = foo.toString();
这段代码的类型检查正常,因为 lib.d.ts 为所有 JavaScript 对象定义了 toString 方法。
如果你在 noLib 选项下,使用相同的代码,这将会出现类型检查错误:
const foo = 123;
const bar = foo.toString(); // Error: 属性 toString 不存在类型 number 上
1.4. tsconfig.json配置文件
在
TS
的项目中,
TS
最终都会被编译
JS
文件执行,
TS
编译器在编译
TS
文件的时候都会先在项目根目录的
tsconfig.json
文件,根据该文件的配置进行编译,默认情况下,如果该文件没有任何配置,
TS
编译器会默认编译项目目录下所有的
.ts
、
.tsx
、
.d.ts
文件。实际项目中,会根据自己的需求进行自定义的配置,下面就来详细了解下
tsconfig.json
的文件配置。
文件选项配置
files : 表示编译需要编译的单个文件列表
"files": [
// 指定编译文件是src目录下的a.ts文件
"scr/a.ts"
include: 表示编译需要编译的文件或目录
"include": [
// "scr" // 会编译src目录下的所有文件,包括子目录
// "scr/*" // 只会编译scr一级目录下的文件
"scr/*/*" // 只会编译scr二级目录下的文件
exclude:表示编译器需要排除的文件或文件夹
默认排除node_modules文件夹下文件
"exclude": [
// 排除src目录下的lib文件夹下的文件不会编译
"src/lib"
extends: 引入其他配置文件,继承配置
// 把基础配置抽离成tsconfig.base.json文件,然后引入
"extends": "./tsconfig.base.json"
compileOnSave:设置保存文件的时候自动编译
vscode暂不支持该功能,可以使用'Atom'编辑器
"compileOnSave": true
执行 tsc --init 生成的ts.config.js会有六个初始设置
"compilerOptions":{
"target":"es2016", // 指定编译成的是哪个版本的js
"module":"commonjs", // 指定要使用的模块化的规范
"esModuleInterop":true, // 兼容JS模块无default的导入
"forceConsistentCasingInFileNames":true, // 兼容JS模块无default的导入
"strict":true, // 所有严格检查的总开关
"skipLibCheck":true // 跳过所有.d.ts文件的类型检查
Vue3中使用TS
在Vue组合式API中它会有默认的自动类型注解,另外我们可以使用泛型进行复杂类型注解。
自动类型注解
<script setup lang="ts">
import { ref } from "vue";
let count = ref(0);
count.value = "123"; // 不能将类型“string”分配给类型“number”。
</script>
手动类型注解
<script setup lang="ts">
import { ref } from "vue";
let count = ref<string|number>(0);
count.value = "123"; // √
</script>
复杂类型注解
<script setup lang="ts">
import { ref } from "vue";
interface List {
let count = ref<string|number>(0);
count.value = "123"; // √
</script>
Vue3 + TS 组件通信
// parent.vue
<my-child :count="count"></my-child>
// my-child
// 1. vue自带的定义方式
defineProps({
count: [Number]
// 2. ts的方式
interface Props({
count: number
defineProps<Props>()
// parent.vue
<my-child @say-hello="sayHello"></my-child>
const sayHello = (message: string) => {
console.log({ message });
// my-child
interface Emits {
(e: "say-hello", message: string): void;
let emit = defineEmits<Emits>();
emit("say-hello", "hello-world");
VueRouter + TS
RouteRecordRaw -> 路由表选项类型
const routes: Array<RouteRecordRaw> = [
path: "/",
name: "home",
component: HomeView,
RouteMeta -> 扩展meta的类型
declare module "vue-router" {
interface RouteMeta {
// 是可选的
isAdmin?: boolean;
// 每个路由都必须声明
requiresAuth: boolean;
RouterOptions -> createRouter的配置类型
RouteLocationNormalized -> 标准化的路由地址
Router -> router的实例类型
调用路由的方式
import { userRouter, useRoute } from 'vue-router'
const router = useRouter() // 类似 this.$router
const route = useRoute() // 类似 this.$route
Vuex +TS
导出key
导出key
重写useStore
使用store
// store.ts
import { createStore, Store, useStore as baseUseStore } from "vuex";
import { InjectionKey } from "vue";
export interface State {
count: number;
// step 3 重写useStore
export function useStore() {
return baseUseStore(key);
// step 1 导入key
export const key: InjectionKey<Store<State>> = Symbol();
export default createStore<State>({
state: {
count: 1,
getters: {},
mutations: {},
actions: {},
modules: {},
// main.ts
import store, { key } from "./store";
// step 2 导出key
app.use(store,key)
// App.vue
import { useStore } from '@/store'
// step 4 使用store
const store = useStore()
console.log(store.state.count)
Pinia如何使用TS
首先在main.ts中注册Pina
import { createPina } from 'pinia'
const pinia = createPinia()
createApp(App).use(pinia).mount('#app')
创建 /stores/counter.ts文件
import { defineStore } from 'pinia'
interface Counter {
counter: number
export const useCounterStore = defineStore('counterStore', {
state: (): Counter => ({
counter: 0
actions: {
add(n : number) {
this,counter += n
在App.vue中使用
import { storeToRefs } from 'pinia
import { useCounterStore } from './stores/counter'
let counterStore = useCounter()
let { counter } = storeToRefs(counterStore)
let handleClick = () => {
counterStore.add(2)
Pinia除了选项式写法外,也支持组合式写法,主要利用的就是Vue组合式API来实现的
import { defineStore } from 'pinia'
impoer { ref } from 'vue'
export const useCounterStore = defineStore('counterStore', () => {
conter = ref<number>(0)
return { counter }
Element Plus中如何使用TS
如果使用Volar,在ts.config.json中通过comiplerOptions.types指定全局组件类型"types": ["element-plus/global"],会有更好的提示。