TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法

我们先创建一个新的 vue 项目:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第1张图片

然后会出来三个选项:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第2张图片

第一个选项是你之前的个人配置。如果你已经用过 vue-cli 创建项目,并且保存了配置项,它就会出来第一个。

第二个选项 default,是默认配置。

第三个选项 Manually select features 是手动配置。

如果我们要用 ts 的话,就选择:Manually select features。

然后它就会出来一些配置给你选择:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第3张图片

我们选完之后,回车。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第4张图片

接下来,它会问你,要不要 class 风格的组件。

class 风格就是 class App extends Vue { ... }

这里我们当然选择 Yes。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第5张图片

然后它就会问你要不要单独的去做 ts 的 polyfills。

我们也可以要。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第6张图片

然后会继续问你要不要 history 的路由模式,这里可以要。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第7张图片

然后会问你使用什么样的 css 预编译器,这里我们选 Less。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第8张图片

然后会问你代码格式化检测你选哪种?这里我们当然选 TSLint。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第9张图片

然后这里是选择代码的语法检查方式。

Lint on sava 是保存就检测。

Lint and fix on commit 是 fix 和 commit 的时候检测。

这里我们可以不需要。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第10张图片

然后它会问你,Babel、ESLint、etc. 这些文件的配置是单独的一个文件配置,还是都放到 package.json 里面。

我们这里选单独的配置文件。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第11张图片

然后这里它会问你,是否需要保存上面的所有配置。

如果你保存了,就是最开始 vue create xxx 的时候,出现的第一个配置项,可以看到我上面的名字是 mumu。

然后在以后的项目中,你就可以直接根据这次的配置去生成项目了。

这里我就选 No 了。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第12张图片

然后它就会自动的去下载依赖模块了。

这里我用的是 Vue CLI 最新的 4.1.2 版本。

 

接下来,我们先说 ts 里面一个及其重要,及其实用的一个东西,就是 ts 的装饰器。

其实装饰器不算是一个语法角度的东西,它其实是一种设计模式

那么 ts 的装饰器是干什么的呢?

ts 的装饰器可以为一个类,也就是 class,来附加一些功能

其实在 Vue CLI 的 ts 项目中,它自己就带了一个装饰器。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第13张图片

@Coponent 的 @ 符号就是装饰器。

Vue 的作者尤大大其实想推广2个东西:

1,他想推广 ts,他希望用 vue 的人都能拿 ts 去写项目。

2,他希望你用 class 来写组件。这是因为他其实在逐渐的像一个方向靠拢,就是他希望 vue 能够越来越多的变成一个程序应有的写法。

如果你在最开始 Vue CLI 3.x 的时候就用了 ts,应该就会很清楚。

那么我们回到正题,这里为什么会有 2 个这样的东西呢?

@Component
export default class HelloWorld extends Vue { }

这个其实只是一个过渡期的形式。

也就是说,只要你愿意,你仍然可以在 @Component 里面写,就像原来的 vue 一样

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第14张图片

然后你也可以写在 class 里面:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第15张图片

这两种写法,vue 都是认可的。

所以从写代码的角度来看, @Component 的存在其实并不是必须的。

它的作用其实是尤大大希望它能够帮我们来完成 vue 的过渡。

因为,毕竟用这个东西的人,大部分都是有 vue 经验的,所以他给你提供了一种方案:你依然可以像原来一样写 vue,然后你也可以用类的方式来写。

而且,它们两个还是共存的。

共存的意思就是:虽然 aaa 和 bbb 它们是分散在两边来写的,如果需要的话,其实在 template 里面,aaa 和 bbb 照样还是可以用的。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第16张图片

上面我们说了 @ 符号,就是装饰器,它可以帮助我们给类去装饰,去附加东西。

那么这里的 @Component 装饰器,它装饰的就是自己下面那个 HelloWorld 这个 class。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第17张图片

 

那么我们了解了装饰器之后,它怎么用呢?

装饰器听起来高大上,其实原理非常的简单。

装饰器它其实就是个函数。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第18张图片

其实这个 fn 你就可以当做一个装饰器。

它的用法,就是加一个 @ 符号:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第19张图片

然后我们编译的时候,就可以看到它报错了。

第一个报错是说,你的 fn 缺少参数,我是要给你传参的,但是你没有接收。

第二个报错是插件的冲突问题,这里和后面编译的时候都可以忽略。解决方法是创建一个 tsconfig.json 或 jsconfig.json 文件,配置:

{"compilerOptions": {"experimentalDecorators": true}} 就可以了。

 

那么参数没有接收是什么意思呢?

因为装饰器这个东西,它毕竟是需要干活的,所以在这个时候,它会给你传一个参数进来。

这个参数,就是你要去处理的那个 class

那么我们给 fn 添加一个参数,并打印出来看看是什么:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第20张图片

可以看到,函数 fn 接收的参数,就是一个 function User 。也就是 class User 的这个构造器本身

那么我们就可以给它加东西了:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第21张图片

但是编译后,它会报错,说 User 身上并没有 a 这个东西。

其实,ts 它一定是要在编译期就得有这个东西。

但是运行时是没有问题的。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第22张图片

可以看到,上图中 12 已经出来了。

但是 ts 检查不到。

所以装饰器的用法不是这么简单,直接往上一放就完事的,这个是过不了 ts 的语法检查的。

 

其实装饰器不止能用于 class,它还能用于属性或者方法

我们可以先给一个属性加上:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第23张图片

可以看到,它又报错了。原因也是因为参数不对。

因为如果你是给类去加一个装饰器,它确实只有一个参数,就是构造函数,也就是类本身

但如果我们去给属性加的时候,这里它报错,是说签名对不上。其实它这里的提示并不全面,就只会说签名对不上。

其实我们的 fn 函数里面现在要接受 3 个参数

第 1 个参数,具体的对象。它是一个 User 类型。

第 2 个参数,你这个属性的名字。它是一个 string 类型。

第 3 个参数,这个属性的值。它是一个 any 类型。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第24张图片

可以看到 value 是 undefined。

原因是我们现在加这个装饰器的时候,它的实例是没有建出来的,所以它就没有 name 这个值。

 

然后我们现在给方法加上:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第25张图片

然后它也会报错,原因也是因为参数不对。

然后我们加上参数,并打印出来:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第26张图片

 

那如果我们想自己实现一个装饰器该怎么做呢?

比如我们在上面最开始举的例子:

现在我们有一个装饰器 addA,还有一个类 User。

我们希望它可以帮助这个类,添加一个 a 属性。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第27张图片

首先,我们上面说过,给类添加装饰器,它这里接收的参数就是一个构造函数,也就是类本身。

那么我们怎么通过构造函数 constructor 来给它加个 a 呢?

我们可以直接通过 constructor.prototype.a 这样的方式来加

因为我们都知道所有的类,都是有原型的,那有了原型,自然就能加东西。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第28张图片

我们打印 obj.a 的时候却报错了。但是 12 却可以打印出来。

报错原因很简单,它说在 User 上面,并没有 a 这个属性。

为什么不存在?因为我们并没有申明这个 a 啊。

所以,我们需要申明一下:

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第29张图片

所以,如果你想要去做这个事的话,就需要让它这个东西,本身要声明一下,就可以了。

 

但是现在会有一个问题,这个 a 我们是写死的 12。

所以我们希望 addA 它是可以传一个参数的。那么我们就在后面添加一个参数 num: number。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第30张图片

然后你会发现它报错了,说 addA 这个函数期待 2 个参数,但是我只得到了 1 个。

这里就很奇怪了,你看 @addA(12) 和 @addA(5) 明明我们都传了啊?

这里需要注意一下,因为实际上装饰器它真的只能接受一个参数。

我们刚才是直接这样用的:

@addA
class User {  }

我们并没有在 @addA 后面加什么东西,说白了,就是我们根本就没把它当函数用。

所以,直接在 addA 函数后面加第二个参数是不行的。

其实我们可以利用高阶函数,也就是对外,我们返回一个函数。

这是因为 @addA 不加括号就能执行,那如果我们在加一个括号,它其实就是给里面那个函数的。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第31张图片

但是它又报错了,说 12 和 5,你是不能放到 Function 类型里面的。

现在就很奇怪了,我们传的参数 12 和 5,明明是给内层函数的。

但它报的错,却说我们的参数赋值给到外层函数去了。

其实装饰器参数是这样的,我们这里的 addA,

它外层接收的是 num: number。

内层接收的是 constructor: Function。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第32张图片

@addA(12)
class User { }

它会自动的帮我们编译成:

@addA(12)(User)
class User { }

所以装饰器其实并不神奇,它就是一个 function,并且是由 ts 来调用。

我们写的 @addA(12) 其实它会自动的帮我们变成 @addA(12)(User)。

这个就是装饰器的本质。

TypeScript基础(五):TS Vue 项目安装,装饰器的作用、原理和实现,TS 在 Vue 中的用法_第33张图片

 

你可能感兴趣的:(TypeScript基础)