# TypeScript
TypeScript 是 JavaScript 的一个超集,大家可以理解为是 JavaScript 的另一种写法。它可以通过 TypeScript 编译器或 Babel 转译为 JavaScript 代码。
参考文档 龙的读书笔记
## TypeScript 的优缺点
优点:
- 类型系统实际上是最好的文档 - 在代码编写时就会提示大部分错误 - 大大增强了编辑器和开发工具的功能,有强大的代码补全和提示 - 他是 JavaScript 的超集,可以直接讲 js 文件重命名为 ts 文件 - 既是编译器提示了错误,但是仍然可以生成 JavaScript 文件
缺点:
- 有一定的学习成本,他的接口、泛型等概念对于前端工程师理解起来可能有困难 - 短期开发会增加开发成本,由于有各种类型声明
## TypeScript 与 Javascript 的区别
TypeScript 中的数据要求带有明确的类型,JavaScript 不要求。
let a: string = "hello";
console.log(a.length);
// 编译成 JS 后的代码为
var a = "hello";
console.log(a.length);
TypeScript 中变量被限制了类型之后,就无法访问该类型中不存在的属性或方法,但 js 中可以
// 一段可以执行的js
let a = 100;
if (a.length !== undefined) {
console.log(a.length);
} else {
console.log("no length");
}
// 我们将上面的js用ts重写
let a: number = 100;
if (a.length !== undefined) {
// error TS2339: Property 'length' does not exist on type 'number'.
console.log(a.length);
} else {
console.log("no length");
}
// 在ts中变量被声明类型后就不能使用不属于它的方法,否则会报错
## 基础数据类型
除了经典的:布尔值 数字 字符串 数组 null underfined object TypeScript 还有:元组 枚举 any void Never
TypeScript 声明时定义了类型,后续使用中不可以改变类型
//布尔值
let bool: boolean = true;
//数字
const num: number = 1;
//字符串
const username: string = "longbao1";
//数组
let arr: number[] = [1, 2, 3]; //这是一个数字数组
let arr1: string[] = ["1,2,3"]; //这是一个字符串数组
//数组泛型写法
let arr2: Array<string> = ["1"];
//元组
// 元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
let x: [string, number] = ["hello", 10];
//枚举类型
enum Color {Red, Green, Blue}
let c: Color = Color.Green;//一个序号和值相互对应的对象。
console.log(c);
上面仅仅是 ts 中一些简单的类型,还有一些比较复杂的类型,大家可以自己了解。 参考文档
听到这里小伙伴们可能已经感觉用 TypeScript 来编写程序好麻烦,各种声明类型。实际上在 TypeScript 里存在类型推论。也就是说在有些没有明确指出类型的地方,类型推论会帮助提供类型。在有些时候我们可以省略掉对类型的声明。
npm install -g typescript
全局安装 ts 编译工具
tsc 文件名.ts
在文件目录内运行命令行,将 ts 文件编译为 js 文件
## 函数
上面我们理解了如何定义一个变量,下面简单的介绍一下如何声明一个函数
//定义函数参数类型
function add(x: number, y: number): number {
//返回值类型
return x + y;
}
//添加?来声明可选参数
function buildName(firstName: string, lastName?: string) {
if (lastName) return firstName + " " + lastName;
else return firstName;
}
## 其他
在 TypeScript 中还有许多的知识,例如:接口、类、继承、泛型、装饰器。由于时长的限制可能就不进行逐一介绍了,简单介绍下面可能用到的一些。
## Vue 与 typescript
详见git 文档
由于 Vue2 底层的缘故,可能对 ts 的使用并不非常友好,在代码提示上还不够方便强大。
<!-- ts 的 Vue 项目与 js 的 Vue 项目的区别还是较大的,写法变化较大。 -->
### 开始一个项目
改造现有的 vue 项目
- vue create vue_and_typescript
- npm i vue-class-component vue-property-decorator
- npm i ts-loader typescript tslint tslint-loader tslint-config-standard
- 然后进行一系列的配置
包说明: vue-class-component vue 官方的 ts 支持包 vue-property-decorator 对 ts 支持包更好封装的装饰器 ts-loader webpack ts 解释器 typescript ts 核心 tslint 语法检查器 tslint-loader webpack 语法检查器 tslint-config-standard 语法规则包
创建新的 vue 项目
- 在创建项目时手动创建,选中 TypeScript 这一项,就可以创建出支持 ts 的 vue 项目。
文件构造:
- shims-tsx.d.ts :ts 的声明文件,在 ts 可以写 jsx - shims-vue.d.ts 声明在 ts 导入 vue 组件 - tsconfig.json 配置文件
// 文件结构
<template>
<div id="app">
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from './components/HelloWorld.vue';
//Component 装饰器,这个装饰器即便没有内容也不能删除
[@Component](/user/Component)({
// 组件注册
components: {
HelloWorld,
},
export default class App extends Vue {
}
})
</script>
### 装饰器
类装饰器
//装饰器内返回一个函数一般就可以传参
function demoDecorator(countValue: number) {
return function (target: any) {
// console.log();
target.prototype.count = countValue;
};
}
@demoDecorator(1000) //装饰器直接写在类的前面,就可以装饰这个类
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
}
const greeter: any = new Greeter("lucy");
console.log(greeter);
// 返回值
// Greeter
// greeting: "lucy"
// __proto__:
// count: 1000
// constructor: ƒ Greeter(message)
// __proto__: Object
方法装饰器
//targetPrototype 类的原型对象、methodName方法名,方法的描述、desc.value就是方法本身
function showPonitDec(param?: string) {
return function (targetPrototype: any, methodName: any, desc: any) {
// 首先将获取到的函数存储下来
const oDescValue = desc.value;
//替换方法本身。参数传递
desc.value = function (...arg: any[]) {
//判断是否传递了事件名、没传递就是事件名相同省略了,
const eventName = param ? param : methodName;
console.log(eventName);
//接收父级传递的自定义函数,这是[@Emit](/user/Emit)的核心
this.$emit(eventName, ...arg);
// 运行函数本身代码,实现了函数合并的效果
oDescValue.apply(this, arg);
};
};
}
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
//没有传递事件名
@showPonitDec()
//传递了参数
showPoint(id: string) {
console.log("old1" + id);
}
}
const point = new Point(1, 2);
point.showPoint("dsvfsdfh");
属性装饰器
// 属性装饰器
function Prop(param?:string){
// targetPrototype 类的原型对象
// propName 属性名
return function(targetPrototype:any,propName:any){
//可传可不传
targetPrototype[propName]=param?param:propName
// 接收prop的值并赋值,实现[@Prop](/user/Prop)的功能
// targetPrototype[propName]=this[param?param:propName]
}
}
class ColorPoint{
x:number
y:number
[@Prop](/user/Prop)('col1or11') color!:string
constructor(x:number,y:number){
this.x=x
this.y=y
}
}
const colorPoint =new ColorPoint(1,2)
console.log(colorPoint.color);
而我们刚刚见到的@Component 其实就是一个类装饰器,将组件装饰到的它下面的对象上。
### ts 中 vue 各部分写法
#### ts 中的 prop 传递数值
//传递
<TodoWrap title="i am title" :count.sync="count" />
//需要在接收prop的页面导入prop
import { Component, Vue, Prop, PropSync } from "vue-property-decorator";
[@Component](/user/Component)
export default class TodoWrap extends Vue {
[@Prop](/user/Prop)(String) title!: string;
[@PropSync](/user/PropSync)("count", { type: Number }) syncedCount!: number;
//接收的变量名以及类型
//在ts中定义函数直接定义,不需要有 methods
changecount() {
this.$emit("update:count", 20000);
}
}
#### 定义函数,传递函数
//App定义函数传给下级组件
export default class App extends Vue {
count = 100;
//定义函数
handleClick(value: number) {
console.log(value);
this.count = value;
}
}
// @handle-click="handleClick" 传递需要用驼峰
//组件接收函数
[@Emit](/user/Emit)("handle-click")
changeCountNew(value: number) {}
//一个函数对应一个Emit,Emit也需要导入
// 可以理解为将两个函数合并了
#### 生命周期
[@Component](/user/Component)({
created(){}
})
#### @Watch
侦听器
//可以对一个数据监听多次,相互之间不会覆盖
[@Watch](/user/Watch)("question", { immediate: true /*(监听配置) */ })
//监听函数
onQuestionChange2(newValue: string, oldValue: string) {
console.log(newValue);
}
### 小结
装饰器语法的使用 @Component :
- 内部可以写组件注册 - 生命周期 - 计算属性
@Prop @Emit @PropSync @Model @VModel(与 ModelSync 功能相似) @ModelSync @Watch