700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > TypeScript+创建Vue3+ts项目

TypeScript+创建Vue3+ts项目

时间:2021-05-15 13:21:21

相关推荐

TypeScript+创建Vue3+ts项目

介绍:

TypeScript是JavaScript的超集,可以理解为进化版的 JavaScript。作为超集TypeScript紧跟 ECMAScript 标准,所以 ES6/7/8/9 等新语法标准都是支持的,而且还在语言层面上,对一些语法进行拓展。比如新增了枚举(Enum)这种在一些语言中常见的数据类型,对类(Class)实现了一些ES6标准中没有确定的语法标准等等。还拥有强大的类型系统在编写代码的时候,就能检测出错误

安装:

npm install -g typescript

一.原始数据类型

//1.数值类型numberconst a: number = 3;//2.null类型let k: null= null;//3.字符串类型stringconst b: string = "1";//4.undefined类型let u: undefined = undefined;//5.布尔类型booleanconst g: boolean = true;//6.数组Array<type>或type[]1.const list1: number[] = [1, 2, 3];2.const list2: Array<number> = [1, 2, 3];//7.对象objectconst i: object = {};

二.TS中补充的六个类型

//1.元组类型:元组可以看做是数组的拓展,它表示已知数组中每一个位置上的元素的类型let tuple: [string, number, boolean];tuple = ["a", 2, false];//上面定义了一个元组 tuple,它包含的三个元素类型是固定的string, number, boolean。//当我们为 tuple 赋值时,各个位置上的元素类型都要对应,元素个数也要一致。tuple[1] = 3;//通过索引给单个的元素赋值,tuple[1]的时候类型为number,所以赋值3是没问题的//2.枚举enum类型:可以给一组数值赋予名字enum Roles {SUPER_ADMIN,ADMIN,USER}//上面定义的枚举类型 Roles 里面有三个值,TypeScript 会为它们每个值分配编号,//默认从 0 开始,依次排列,所以它们对应的值是SUPER_ADMIN = 0,ADMIN = 1,USER = 2const superAdmin = Roles.SUPER_ADMIN;console.log(superAdmin); // 0//使用的时候,就可以使用名字而不需要记数字和名称的对照关系enum Roles {SUPER_ADMIN = 11,ADMIN,USER}//可以为每个值都赋予不同的、不按顺序排列的值//3.Any类型:即任意类型let value: any;value = 123;value = "abc";value = false;//我们定义变量 value,指定它的类型为 any,接下来赋予任何类型的值都是可以的const array: any[] = [1, "a", true];//还可以在定义数组类型时使用 any 来指定数组中的元素类型为任意类型//4.void类型:表示没有任意类型,就是什么类型都不是,这在我们定义函数,函数没有返回值时会用到const consoleText = (text: string): void => {console.log(text);};//这个函数没有返回任何的值,所以它的返回类型为 void//void 类型的变量只能赋值为 undefined 和 null,其他类型不能赋值给 void 类型的变量//5.never类型:指那些永不存在的值的类型const errorFunc = (message: string): never => {throw new Error(message);};//errorFunc 函数总是会抛出异常,所以它的返回值类型是 never,用来表明它的返回值是永不存在的//6.unknown:表示未知的类型,另一种是 anylet value: unknown;value = true; // OKvalue = 42; // OKvalue = "Hello World"; // OKvalue = []; // OKvalue = {}; // OKvalue = Math.random; // OKvalue = null; // OKvalue = undefined; // OKvalue = new TypeError(); // OKvalue = Symbol("type"); // OK//unknown 类型只能被赋值给 any 类型和 unknown 类型本身let value1: unknown = value; // OKlet value2: any = value; // OK

三.指定变量的类型

//这里指定person 参数类型为 string,所以user的值必须传string类型function sayHello(person: string) {return 'Hello, ' + person;}let user = 'Tom';console.log("指定变量的类型",sayHello(user));//Hello, Tom//判断参数类型function sayHello(person: string) {if (typeof person === 'string') {return 'Hello, ' + person;} else {throw new Error('person is not a string');}}let use = "111";//use的值必须是string类型,否则报错 throw new Error('person is not a string');console.log("判断参数类型",sayHello(use));

自动编译文件

如果直接使用tsc指令,则可以自动将当前项目下的所有ts文件编译为js文件。

但是能直接使用tsc命令的前提时,要先在项目根目录下创建一个ts的配置文件 tsconfig.json

tsconfig.json是一个JSON文件,添加配置文件后,只需只需 tsc 命令即可完成对整个项目的编译

具体配置:

{"compilerOptions": {"target": "esnext","module": "esnext","moduleResolution": "node","strict": true,"jsx": "preserve","sourceMap": true,"resolveJsonModule": true,"esModuleInterop": true,"lib": ["esnext", "dom"],"types": ["vite/client"],"paths": {"@/*": ["./src/*"],"/@/*": ["./src/*"]}},"include": ["src/**/*"]}

四.TypeScript 断言

// “尖括号” 语法let someValue: any = "this is a string";console.log(someValue); //this is a stringlet strLength: number = (<string>someValue).length;console.log(strLength); // 16//as 语法let someValue: any = "this is a string";console.log(someValue);//this is a stringlet strLength: number = (someValue as string).length;console.log(strLength);//16

五.接口

接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约

//使用interface来定义接口//例子:interface userInfo {name: string;age: number;address?: string; //问号代表该属性可添加可不添加}function getUserInfo(u: userInfo) {console.log(u.name); //张三console.log(u.age); //24console.log(u.address); //北京}let user1 = { name: "张三", age: 24, address: "北京" };getUserInfo(user1);

//.只读属性(readonly):如果我们希望对象属性只能在对象刚创建的时候修改其值//可以在属性名前制定readonly来指定只读属性interface Point {readonly x: number;readonly y: number;}let p1: Point = { x: 10, y: 20 };p1.x = 3;console.log("接口的只读属性", p1);//{x: 3, y: 20}//定义只读数组let a: number[] = [1, 2, 3, 4];let ro: ReadonlyArray<number> = a;ro[0] = 12; //索引a = ro;console.log("定义只读数组", a);//[12, 2, 3, 4]

//用接口定义函数的形状//对等号左侧进行类型限制,可以保证以后对函数名赋值时保证参数个数、参数类型、返回值类型不变interface SearchFunc {(source: string, subString: string): boolean;}let mySearch: SearchFunc;mySearch = function(source: string, subString: string) {return source.search(subString) !== -1;}

//数组类型:通过索引得到的类型,只能是number或者stringinterface StringArray {[index: number]: string;}let myArray: StringArray = ["Bob", "Fred"];console.log(myArray);//['Bob', 'Fred']let myStr: string = myArray[0];console.log(myStr);//Bob

//类类型:就是一个类去实现接口,而不是直接把接口拿来用,写法就是 class implements interfaceinterface IClock {/*定义了一个接口 这个接口中有一个属性和一个方法*/currentTime: Date;//属性getTime(d: Date);//方法}/*Time类实现IClock接口*/class Time implements IClock {currentTime: Date;getTime(d: Date) {this.currentTime = d;}}

六.函数的类型

// 函数声明(Function Declaration)function sum(x, y) {return x + y;}//函数 function 函数名(变量:类型,变量:类型):返回值类型 {//return a+b;// }function sum(x: number, y: number): number {return x + y;}sum(1, 2);// 函数表达式(Function Expression)let mySum = function (x, y) {return x + y;};

//可选参数:可选参数必须接在必需参数后面function buildName(firstName: string, lastName?: string) {if (lastName) {return firstName + ' ' + lastName;} else {return firstName;}}let tomcat = buildName('Tom', 'Cat');console.log(tomcat);//Tom Catlet tomtom = buildName('Tom');console.log(tomtom);//Tom

七.声明文件:必需以.d.ts为后缀

declare var 声明全局变量declare var jQuery: (selector: string) => any;jQuery('#foo');declare function 声明全局方法declare class 声明全局类declare enum 声明全局枚举类型declare namespace 声明(含有子属性的)全局对象interface 和 type 声明全局类型export 导出变量export namespace 导出(含有子属性的)对象export default ES6 默认导出export = commonjs 导出模块export as namespace UMD 库声明全局变量declare global 扩展全局变量declare module 扩展模块/// <reference /> 三斜线指令

通常我们会把声明语句放到一个单独的文件(jQuery.d.ts)中,这就是声明文件

八.内置对象

//ECMAScript 标准提供的内置对象有:Boolean、Error、Date、RegExp,在TypeScript 中的定位为let b: Boolean = new Boolean(1);//{true}let e: Error = new Error('Error occurred');//Error: Error occurredlet d: Date = new Date();//中国标准时间let r: RegExp = /[a-z]/;///[a-z]///DOM 和 BOM 提供的内置对象有:Document、HTMLElement、Event、NodeListlet body: HTMLElement = document.body;let allDiv: NodeList = document.querySelectorAll('div');document.addEventListener('click', function(e: MouseEvent) {// Do something});

九.类

类(Class):定义了一件事物的抽象特点,包含它的属性和方法对象(Object):类的实例,通过new生成面向对象(OOP)的三大特性:封装、继承、多态封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如CatDog都继承自Animal,但是分别实现了自己的eat方法。此时针对某一个实例,我们无需了解它是Cat还是Dog,就可以直接调用eat方法,程序会自动判断出来应该如何执行eat存取器(getter & setter):用以改变属性的读取和赋值行为修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如public表示公有属性或方法抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口

一.ES6 中类的用法

class Animal {public name;public constructor(name) {this.name = name;}}let ak = new Animal('Jack');console.log(ak.name); // Jackak.name = 'Tom';console.log(ak.name); // Tom

使用class定义类,使用constructor定义构造函数。

通过new生成新实例的时候,会自动调用构造函数。

class Animal {public name;constructor(name) {this.name = name;}sayHi() {return `My name is ${this.name}`;}}let a = new Animal('Jack');console.log(a.sayHi()); // My name is Jack

类的继承§

使用extends关键字实现继承,子类中使用super关键字来调用父类的构造函数和方法。

class Cat extends Animal {constructor(name) {super(name); // 调用父类的 constructor(name)console.log(this.name);}sayHi() {return 'Meow, ' + super.sayHi(); // 调用父类的 sayHi()}}let c = new Cat('Tom'); // Tomconsole.log(c.sayHi()); // Meow, My name is Tom

存取器§

使用 getter 和 setter 可以改变属性的赋值和读取行为:

class Animal {constructor(name) {this.name = name;}get name() {return 'Jack';}set name(value) {console.log('setter: ' + value);}}let a = new Animal('Kitty'); // setter: Kittya.name = 'Tom'; // setter: Tomconsole.log(a.name); // Jack

静态方法§

使用static修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:

class Animal {static isAnimal(a) {return a instanceof Animal;}}let a = new Animal('Jack');Animal.isAnimal(a); // truea.isAnimal(a); // TypeError: a.isAnimal is not a function

二.TypeScript 中类的用法§

public private 和 protected§

TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是publicprivateprotected

public修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是publicprivate修饰的属性或方法是私有的,不能在声明它的类的外部访问protected修饰的属性或方法是受保护的,它和private类似,区别是它在子类中也是允许被访问的

class Animal {public name;public constructor(name) {this.name = name;}}let a = new Animal('Jack');console.log(a.name); // Jacka.name = 'Tom';console.log(a.name); // Tom

name被设置为了public,所以直接访问实例的name属性是允许的。

很多时候,我们希望有的属性是无法直接存取的,这时候就可以用private了:

class Animal {private name;public constructor(name) {this.name = name;}}let a = new Animal('Jack');console.log(a.name);a.name = 'Tom';// index.ts(9,13): error TS2341: Property 'name' is private and only accessible within class 'Animal'.// index.ts(10,1): error TS2341: Property 'name' is private and only accessible within class 'Animal'.

TypeScript 编译之后的代码中,并没有限制private属性在外部的可访问性。

上面的例子编译后的代码是:

var Animal = (function () {function Animal(name) {this.name = name;}return Animal;})();var a = new Animal('Jack');console.log(a.name);a.name = 'Tom';

使用private修饰的属性或方法,在子类中也是不允许访问的:

class Animal {private name;public constructor(name) {this.name = name;}}class Cat extends Animal {constructor(name) {super(name);console.log(this.name);}}// index.ts(11,17): error TS2341: Property 'name' is private and only accessible within class 'Animal'.

protected修饰,则允许在子类中访问

class Animal {protected name;public constructor(name) {this.name = name;}}class Cat extends Animal {constructor(name) {super(name);console.log(this.name);}}

给类加上 TypeScript 的类型

class Animal {name: string;constructor(name: string) {this.name = name;}sayHi(): string {return `My name is ${this.name}`;}}let a: Animal = new Animal('Jack');console.log(a.sayHi()); // My name is Jack

类与接口

接口(Interfaces)的另一个用途,对类的一部分行为进行抽象。

类实现接口§

实现(implements)是面向对象中的一个重要概念。一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用implements关键字来实现。这个特性大大提高了面向对象的灵活性。

举例来说,门是一个类,防盗门是门的子类。如果防盗门有一个报警器的功能,我们可以简单的给防盗门添加一个报警方法。这时候如果有另一个类,车,也有报警器的功能,就可以考虑把报警器提取出来,作为一个接口,防盗门和车都去实现它:

interface Alarm {alert(): void;}class Door {}class SecurityDoor extends Door implements Alarm {alert() {console.log('SecurityDoor alert');}}class Car implements Alarm {alert() {console.log('Car alert');}}

一个类可以实现多个接口:

interface Alarm {alert(): void;}interface Light {lightOn(): void;lightOff(): void;}class Car implements Alarm, Light {alert() {console.log('Car alert');}lightOn() {console.log('Car light on');}lightOff() {console.log('Car light off');}}

上例中,Car实现了AlarmLight接口,既能报警,也能开关车灯。

接口继承接口§

接口与接口之间可以是继承关系:

interface Alarm {alert(): void;}interface LightableAlarm extends Alarm {lightOn(): void;lightOff(): void;}

这很好理解,LightableAlarm继承了Alarm,除了拥有alert方法之外,还拥有两个新方法lightOnlightOff

接口继承类§

常见的面向对象语言中,接口是不能继承类的,但是在 TypeScript 中却是可以的:

class Point {x: number;y: number;constructor(x: number, y: number) {this.x = x;this.y = y;}}interface Point3d extends Point {z: number;}let point3d: Point3d = {x: 1, y: 2, z: 3};

为什么 TypeScript 会支持接口继承类呢?

实际上,当我们在声明class Point时,除了会创建一个名为Point的类之外,同时也创建了一个名为Point的类型(实例的类型)。

所以我们既可以将Point当做一个类来用(使用new Point创建它的实例):

class Point {x: number;y: number;constructor(x: number, y: number) {this.x = x;this.y = y;}}const p = new Point(1, 2);

也可以将Point当做一个类型来用(使用: Point表示参数的类型):

class Point {x: number;y: number;constructor(x: number, y: number) {this.x = x;this.y = y;}}function printPoint(p: Point) {console.log(p.x, p.y);}printPoint(new Point(1, 2));

这个例子实际上可以等价于:

class Point {x: number;y: number;constructor(x: number, y: number) {this.x = x;this.y = y;}}interface PointInstanceType {x: number;y: number;}function printPoint(p: PointInstanceType) {console.log(p.x, p.y);}printPoint(new Point(1, 2));

上例中我们新声明的PointInstanceType类型,与声明class Point时创建的Point类型是等价的。

所以回到Point3d的例子中,我们就能很容易的理解为什么 TypeScript 会支持接口继承类了:

class Point {x: number;y: number;constructor(x: number, y: number) {this.x = x;this.y = y;}}interface PointInstanceType {x: number;y: number;}// 等价于 interface Point3d extends PointInstanceTypeinterface Point3d extends Point {z: number;}let point3d: Point3d = {x: 1, y: 2, z: 3};

当我们声明interface Point3d extends Point时,Point3d继承的实际上是类Point的实例的类型。

换句话说,可以理解为定义了一个接口Point3d继承另一个接口PointInstanceType

所以「接口继承类」和「接口继承接口」没有什么本质的区别。

值得注意的是,PointInstanceType相比于Point,缺少了constructor方法,这是因为声明Point类时创建的Point类型是不包含构造函数的。另外,除了构造函数是不包含的,静态属性或静态方法也是不包含的(实例的类型当然不应该包括构造函数、静态属性或静态方法)。

换句话说,声明Point类时创建的Point类型只包含其中的实例属性和实例方法:

class Point {/** 静态属性,坐标系原点 */static origin = new Point(0, 0);/** 静态方法,计算与原点距离 */static distanceToOrigin(p: Point) {return Math.sqrt(p.x * p.x + p.y * p.y);}/** 实例属性,x 轴的值 */x: number;/** 实例属性,y 轴的值 */y: number;/** 构造函数 */constructor(x: number, y: number) {this.x = x;this.y = y;}/** 实例方法,打印此点 */printPoint() {console.log(this.x, this.y);}}interface PointInstanceType {x: number;y: number;printPoint(): void;}let p1: Point;let p2: PointInstanceType;

上例中最后的类型Point和类型PointInstanceType是等价的。

同样的,在接口继承类的时候,也只会继承它的实例属性和实例方法。

创建Vue3+ts项目:

node版本(14.x以上)、Vue-cli版本(4.x以上)

vue create 项目名--------选择自定义创建项目

光标到对应行,然后按空格即可选中需要的配置

项目目录:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。