TypeScript basis (five): the role of TS Vue project installation, decorators, principles and implementation, TS usage of Vue

Let's create a new project vue:

Then will come out three options:

The first option is your previous personal configuration. If you have used vue-cli create a project, and save the configuration items, it will come out first.

The second option is default, is the default configuration.

The third option is to manually configure Manually select features.

If we use ts, then choose: Manually select features.

Then it will come out to give you some configuration options:

After we finished selecting, press Enter.

Next, it will ask you, you do not class-style components.

Our original style is let app = new Vue ()

style class is class App extends Vue {...}

Of course, here we choose Yes.

Then it will ask you not to do it alone polyfills ts of.

We can also be.

Then routing mode will continue to ask you not to history, where you can be.

Then I will ask you what kind of css pre-compiler, here we have chosen Less.

Then we will ask you to format the code to detect what you choose? Of course, here we choose TSLint.

Here is the syntax check then choose the way codes.

Lint on sava is saved on testing.

Lint and fix on commit and commit a fix when detected.

Here we can not.

Then it will ask you, Babel, ESLint, etc. These configuration files is a separate configuration file, or are put package.json inside.

Here we choose a separate profile.

Here then it will ask you if you need to save all the configuration above.

If you save, that is the beginning vue create xxx, when the first configuration items appear, you can see my name above is mumu.

Then after the project, you can generate the configuration to direct the project.

Here I chose the No.

Then it will automatically download to the module dependent.

Here I use Vue CLI latest 4.1.2 version.

 

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

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

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

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

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

@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 一样

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

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

所以 @Component 的存在其实并不是必须的。

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

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

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

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

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

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

 

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

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

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

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

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

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

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

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

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

 

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

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

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

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

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

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

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

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

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

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

但是 ts 检查不到。

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

 

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

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

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

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

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

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

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

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

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

可以看到 value 是 undefined。

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

 

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

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

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

 

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

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

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

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

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

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

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

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

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

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

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

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

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

 

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

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

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

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

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

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

@addA
class User {  }

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

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

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

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

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

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

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

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

它外层接收的是 num: number。

内层接收的是 constructor: Function。

@addA(12)
class User { }

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

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

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

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

这个就是装饰器的本质。

 

发布了62 篇原创文章 · 获赞 3 · 访问量 4774

Guess you like

Origin blog.csdn.net/weixin_43921436/article/details/104082531