安装
安装
代码语言:javascript复制npm install -g typescript
打开项目文件夹
代码语言:javascript复制tsc -init
编译
代码语言:javascript复制tsc ts01.ts
监听编译
代码语言:javascript复制tsc -w
监听编译某个文件
代码语言:javascript复制tsc -w ts01.ts
修改编译生成JS的位置和目标语法
打开tsconfig.json
,修改outDir的值,并解除注释
{
"compilerOptions": {
"target": "es3",
"outDir": "./js/"
}
}
默认会转成ES6,这里建议转换为ES3或ES5来兼容大多数浏览器。
语法
数据类型
代码语言:javascript复制let num: number = 1;
let str: string = "hello";
let b: boolean = true;
let n: null = null;
let un: undefined = undefined;
let f: any = 1;
// 获取类型
console.log("typeof(str):" typeof(str))
// 数组
let arr1: Array<number> = [1, 2, 3];
let arr2: number[] = [1, 2, 3];
let arr3: string[] = ["aa", "bb", "cc"];
let arr4: Array<number | string> = [1, "aa", 3];
// 元组
let tup: [string, string, number] = ['Dylan', 'male', 23];
console.log("typeof(tup):" typeof(tup))
数组和元组的区别?
元组可以理解为一个固定长度,每一项元素类型都确定的数组。
我们看一个示例
代码语言:javascript复制let tup: [string, string, number] = ['Dylan', 'male', 23];
tup.push("123");
tup[3] = 123;
示例2
代码语言:javascript复制let tup: [string, string, number] = ['Dylan', 'male', 23];
tup.pop();
tup[2] = 456;
这个示例中我们可以发现元组的几个问题:
- 虽然长度固定,但是我们可以push元素,使之长度超过定义的长度,不会报错。但是根据下标取值的时候不能超过定义时的长度。
- push超出长度,转换的js是能够正常运行的,并且打印结果也是包含超出长度的元素,所以不建议通过push添加元素,建议通过下标设置。
- push的时候数据类型可以是定义的时候所包含的类型,不能是其它类型。
- 根据下标赋值时类型必须和定义的时候一样。
- pop删除元素后,我们依旧可以通过下标赋值。
类
接口 类 接口的实现 类的集成 与 方法重载
代码语言:javascript复制interface Person {
run():void;
}
class Men implements Person {
name: string;
age: number;
constructor(name:string,age:number) {
this.name = name;
this.age = age;
}
run(): void {
console.log("run");
}
talk(): void;
talk(str:string): void;
talk(num:number): void;
talk(str:string,num:number): void;
talk(par1?:any,par2?:any) {
if (par1 == undefined && par2 == undefined) {
console.log("method 1");
}
else if (par2 == undefined) {
if (typeof par1 == "string") {
console.log("method 2");
}
else if (typeof par1 == "number") {
console.log("method 3");
}
} else {
console.log("method 4");
}
}
}
class SuperMen extends Men{
}
let men = new Men("小明", 18);
men.talk();
men.talk("小明");
men.talk(18);
men.talk("小明",18);
结果可以看到
代码语言:javascript复制method 1
method 2
method 3
method 4
VUE2集成TS
新项目创建时可以直接选择ts,这里主要说旧项目升级的情况。
安装依赖
代码语言:javascript复制npm i vue-class-component vue-property-decorator --save
npm i ts-loader typescript tslint tslint-loader tslint-config-standard -D
配置vue.config.js添加下面的代码
代码语言:javascript复制module.exports = {
configureWebpack: {
resolve: { extensions: [".ts", ".tsx", ".js", ".json"] },
module: {
rules: [
{
test: /.ts$/,
exclude: /node_modules/,
enforce: 'pre',
loader: 'tslint-loader'
},
{
test: /.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
appendTsSuffixTo: [/.vue$/],
}
}
]
}
},
}
新建tsconfig.json放在项目根目录
代码语言:javascript复制{
"compilerOptions": {
"allowJs": true,
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
在src根目录下添加两个TS文件
shims-tsx.d.ts
// shims-tsx.d.ts src目录下
import Vue, { VNode } from 'vue';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {}
interface IntrinsicElements {
[elem: string]: any;
}
}
}
新建shims-vue.d.ts
// shims-vue.d.ts src目录下
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
//为了TypeScript做的适配定义文件,因为.vue文件不是一个常规的文件类型,
//TypeScript是不能理解vue文件是干嘛的,加这一段是是告诉 TypeScript,vue文件是这种类型的。
//没有这个文件,会发现 import 导入的所有.vue类型的文件都会报错。
//axios报错
declare module 'axios' {
interface AxiosInstance {
(config: AxiosRequestConfig): Promise<any>
}
}
添加tslint.json
{
"extends": "tslint-config-standard",
"globals": {
"require": true
}
}
main.js
改成main.ts
配置vue.config.js
的入口为main.ts
pages: {
index: {
entry: 'src/main.ts',
}
},
安装@typescript-eslint/parser
将eslint校验改成@typescript-eslint/parser
npm install @typescript-eslint/parser --save
更改.eslintrc.js
parserOptions: {
parser: '@typescript-eslint/parser'
},
代码格式
新旧写法对比
原写法
代码语言:javascript复制<script>
export default {
name: 'xx',// 组件名
components: {},// 组件
props: {},// 父组件传递来的值
data() { // 属性
return {};
},
computed:{}, // 计算属性
watch:{},// 监听器
mounted() {}, // 生命周期钩子函数
methods: {} // 方法
};
</script>
新写法(TS)
代码语言:javascript复制<template>
<div class="home">
<HelloWorld :msg="message" />
{{ computedMsg }}
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch, Emit } from "vue-property-decorator";
import HelloWorld from "@/components/HelloWorld.vue";
@Component({
components: {
HelloWorld,
},
})
export default class Home extends Vue {
// props
@Prop({
type: Number,
default: 1,
required: false,
})
propA?: number;
@Prop()
propB?: string;
// data
public message = "你好 TS";
// computed
public get computedMsg(): string {
return "这里是计算属性" this.message;
}
// watch属性
@Watch("propA", {
deep: true,
})
public test(newValue: string, oldValue: string): void {
console.log("propA值改变了" newValue " oldValue:" oldValue);
}
// $emit
// 原来写法:this.$emit('mysend',this.message)
// 现在直接写 this.bindSend()
@Emit("mysend")
bindSend(): string {
return this.message;
}
// mounted 生命周期钩子函数
mounted(): void {
console.info("mounted");
this.mymethod();
}
// methods中的方法
public mymethod(): void {
this.bindSend();
}
}
</script>
$emit
对比
代码语言:javascript复制count = 0
// this.count = n; this.$emit('add-to-count', n)
@Emit("add-to-count")
addToCount(n: number) {
this.count = n;
}
// this.count = 0; this.$emit('reset');
@Emit("reset")
resetCount() {
this.count = 0;
}
// this.$emit('return-value', 10)
@Emit('return-value')
returnValue() {
return 10;
}
// 相当于 this.$emit('on-input-change', num 1, num)
@Emit("on-input-change")
onInputChange(num: number) {
return num 1;
}
// 相当于
// const promise = new Promise((resolve) => {
// setTimeout(() => {
// resolve(20)
// }, 0)
// })
//
// promise.then((value) => {
// this.$emit('promise', value)
// })
@Emit()
promise() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(20);
}, 0);
});
}
从上面的示例可以看出
方法名就是
$emit
的第一个参数,除非设置了别名。 方法的返回值为$emit
第二个参数。 方法的传参是$emit
的第三个参数,如果方法没有返回值,则为第二个参数。 执行顺序为先执行方法体内的代码,再$emit
。