TypeScript是由微软开发的一个JavaScript超集,主要提供了类型系统和对ES6的支持。正如TypeScript的官网所说:node
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.译:TypeScript是JavaScript的类型化超集,可以编译为纯JavaScript语言。typescript
使用TypeScript,可以校验变量的类型,正由于可以校验变量的类型,它弥补了JavaScript的语法中,弱类型、动态类型语言的缺陷。TypeScript声明的变量是一种静态类型,在代码编译时报错,相比JavaScript的运行时报错,可以提早发现代码错误,及时纠正。npm
TypeScript静态类型不只指变量的类型不可修改,同时也说明,变量中存在的方法和属性也基本肯定了下来。canvas
如下是对TypeScript语法的基础知识的梳理,包含的内容如思惟导图所示。数组
安装TypeScript以前,先安装一下node。
全局安装TypeScript函数
npm install typescript -g
可能这样会报没有权限的错误,这时在前面加sudo(mac为例),而后输入密码能解决这个问题。若是要安装指定版本,加@版本号。优化
sudo npm install typescript@3.6.4 -g
新建一个ts文件this
mkdir demo1.ts
里面先写点东西,以方便后面的操做。spa
const count11: number = 1; console.log(count11);
而后命令行执行:插件
tsc demo1.ts
tsc表示把ts文件编译成js文件。随后能够看到目录中多出一个demo1.js的文件,接着执行:
node demo1.js
在控制台中能看到打印出的1,就是count11这个变量值。
至此,能够看到从编译ts文件到控制台打印输出结果,须要分两步,但这里有个更好的方法,全局安装一个叫ts-node的插件能够进行优化,直接在控制台输出结果,但没法生成编译后但js文件。
这里须要注意的是,须要全局安装ts-node,试过局部安装了一下行不通。
全局安装ts-node
sudo npm install ts-node -g
而后想要执行哪一个文件,就直接:
ts-node 那个文件.ts
TypeScript的静态类型包括基础类型和对象类型,基础类型有number、string、void、boolean、null、undefined......对象类型有对象、数组、类、函数。
// 基础类型举例 const num1: number = 1; // number const str1: string = 'abcd'; // string const nothing: null = null; //null const uf: undefined = undefined; // undefined const right: true = true; // boolean function func1(): void { // void,表示函数没有返回值 console.log('void'); } console.log(num1, str1, nothing, uf, right); func1();
// 对象类型举例 // 对象 const obj1: { height: number, width: number } = { height: 100, width: 100 }; // 数组 const arr1: number[] = [1, 2, 3]; // 这里表示的是数组每一个元素都是number类型 // 类 class Geometry { vector: number; face: number } const geom1: Geometry = new Geometry(); geom1.vector = 8; geom1.face = 6; // 函数 const addXY: (x: number, y: number) => number = (x, y) => { return x + y; } // 上面函数等价于 const addXY = (x: number, y: number): number => { return x + y; } console.log(obj1.height, obj1.width); console.log(arr1); console.log(geom1.vector, geom1.face); console.log(addXY(1, 1));
类型注解的意思是,须要明确地写出变量的类型,而类型推断指的是不须要明确地指定变量的类型。通常可以由Typescript进行类型推断的变量不须要进行类型注解,这个最多见的就是直接像JavaScript那样声明赋值给了一个变量,那么TypeScript就能够推断这个变量是对应的类型,怎么检测到这个变量的类型呢?使用vs code能够查看。
举个例子。
一、类型注解的例子
// 类型注解 let num2: number; num2 = 2;
若是是声明、赋值分开写,又没有类型注解,则没法作到类型推断,这时,类型是any。
// 没法进行类型推断 num2的类型显示any let num2; num2 = 2;
二、类型推断的例子
// 类型推断 let num3 = 133;
// 类型推断 const obj2 = { left: 50, top: 100, radius: '50%' }
如下这个例子,说明了ts没法分析变量的类型,致使变量类型成了any。因此这里是须要用类型注解的。
function addXY2(x, y) { return x + y; } const totals2 = addXY2(1, 7);
使用了类型注解后,totals2变量类型肯定了,而不是以前的any。
function addXY2(x: number, y: number) { return x + y; } const totals2 = addXY2(1, 7);
前面写过静态类型为函数类型,指的是一个函数做为变量,也就是变量是函数类型的变量。而这里的函数相关类型指的是一个函数自身,内部的返回值类型和函数参数的解构。
函数的返回值能够是静态类型,好比number、string、boolean、类class、数组等等。
function addXY3 (x: number, y: number): number[] { return [x + y]; } const totals3 = addXY3(1, 8); console.log(totals3);
function addXY3 (x: number, y: number): string { return x + y + 'px'; } const totals3 = addXY3(1, 8); console.log(totals3);
class computedWidth { width: number; } function addXY3 (x: number, y: number): computedWidth { return { width: x + y }; } const totals3 = addXY3(1, 8); console.log(totals3);
有两个特殊的须要注意一下。
void指的是函数没有返回值,一般在写JavaScript的代码时,写的函数会存在没有返回值的状况,这时使用void便能很好地指明函数没有返回值,一旦不当心多写了return xxx; 便会报错,及时纠正。
never指的是函数永远不会执行到最后。
// never function addXY5(x: number, y: number): never { throw new Error(); console.log(x + y); // 这一行没法执行到 }
当函数的参数是一个对象的时候,须要注意参数的解构赋值。以前有写过函数的参数的类型注解,但那些都是像number、string这样的类型,而像对象类型的参数的类型注解尚未提过。
若是参数是对象类型,须要这样写。
// 函数参数解构正确写法 function addXY4({ x, y }: { x: number, y: number }): number { return x + y; } const totals4 = addXY4({ x: 2, y: 7 });
而不是这样写,会报错。
// 函数参数解构错误写法 function addXY4({ x: number, y: number }): number { return x + y; } const totals4 = addXY4({ x: 2, y: 7 });
// 数组 const strArr: string[] = ['a', 'c', 'b']; const arrAny: (number | string | boolean)[] = ['1', 2, true]; const objArr: { width: number, height: number }[] = [{ width: 100, height: 100 }];
// 使用类型别名 type type ComputedArea = { width: number, height: number }; const objArr2: ComputedArea[] = [{ width: 50, height: 10 }];
// class的状况 class Geometry{ left: number; top: number; id: string; } const geomList1: Geometry[] = [ { left: 100, top: 100, id: 'AB001' }, new Geometry() ]; geomList1[1].left = 200; geomList1[1].top = 200; geomList1[1].id = 'AB002'; console.log(geomList1);
//元组,与数组的区别是元素的类型按顺序指定,不可错位 const student1: [string , string , number] = ['a001', 'Tom', 23];
// 写个复杂点的 const studentList1: [string, string ,number][] = [ ['a001', 'Tom', 22], ['a002', 'Jerry', 23], ['a003', 'Jane', 23] ] console.log(studentList1);
interface接口的做用是把一些共有的属性和方法提出来放到接口里面,接口可供变量使用,做为一个对象类型(对象、函数等)。interface与type类型别名的区别是,interface只能是对象类型,而type能够是其余的基础类型,不单是对象类型。
接口能够定义只读模式的属性,使用readonly标识。
接口中的属性有时不是全部使用这个接口的变量都须要,这时能够在属性名与冒号之间加上一个问号“?”,这个属性将做为可选属性使用。
有时使用接口的变量有本身的属性,而不是接口中定义的,这时,若是在接口中加上[propName: string]: any,将表示使用这个接口的变量能够自定义本身的属性而不须要在接口中存在。
以上所列出的接口的一些特色,在如下的代码中举了些例子。
interface Person { name: string, age?: number, readonly id: string, [propName: string]: any } function getName (person: Person): string { return person.name; } function setName (person: Person, name: string): void { person.name = name; } const Jane = getName({ name: 'Jane', age: 23, id: '0a001', weight: '60kg' }); const resetJane = setName({ name: 'Jane', id: '0a002' }, 'Tom');
class John implements Person { name: 'abcd'; id: '0a003'; }
// interface interface Person { name: string, age?: number, readonly id: string, [propName: string: any } interface female extends Person { tall: string }
// 类的定义 class Geometry { counts = 7; getCounts() { return this.counts; } } const geom6 = new Geometry(); console.log(geom6.getCounts());
// 类的继承 class Geometry { counts = 7; getCounts() { return this.counts; } } class Vector2 extends Geometry { getVectors () { return 8; } } const geom6 = new Vector2(); console.log(geom6.getCounts()); console.log(geom6.getVectors());
若是在子类里面又重写了一遍父类的方法或属性,子类的会覆盖父类的。
class Vector2 extends Geometry { counts = 0; getCounts() { return this.counts; } getVectors () { return 8; } }
若是不想子类里重写的方法、属性覆盖父类,那么能够使用super。
class Geometry { counts = 7; getCounts() { return this.counts; } } class Vector2 extends Geometry { getCounts() { return super.getCounts() + 9; } getVectors () { return 8; } } const geom6 = new Vector2(); console.log(geom6.getCounts()); console.log(geom6.getVectors());
// 类的访问类型--public class Canvas1 { width: string; // 默认是public public height: string; // 能够在子类、类的外部使用 getWidth() { return this.width; } } class SubCanvas1 extends Canvas1 { getHeight() { console.log(this.height); } } const subCanvas1 = new SubCanvas1(); subCanvas1.height = '100px'; console.log(subCanvas1.height);
// 类的访问类型--private class Canvas1 { private width: string; // 只容许类内使用,在子类或类的外部使用都不行 public height: string; getWidth() { return this.width; } }
// 类的访问类型--protected class Canvas1 { private width: string; // 只容许类内使用 public height: string; getWidth() { return this.width; }; protected background: string; // 容许在类的内部及子类中访问,类外不可访问 } class SubCanvas1 extends Canvas1 { getHeight() { console.log(this.height); } getBackground() { console.log(this.background); } }
// 类的构造器 class Canvas2 { // 传统写法 public width: string; constructor(width: string) { this.width = width; } } const canvas2 = new Canvas2('100px'); console.log(canvas2.width);
// 类的构造器 class Canvas2 { // 简化写法 constructor(public width: string) {} } const canvas2 = new Canvas2('100px'); console.log(canvas2.width);
// 子类有构造器,那么子类要手动调用一下父类的构造器,不管父类有没有写构造器 class Canvas2 { // 简化写法 constructor (public width: string) {} } class SubCanvas2 extends Canvas2 { constructor (public id: number) { super('100px'); // 手动调用父类构造器,有参传参 } } const subCanvas2 = new SubCanvas2(10001); console.log(subCanvas2);
至此,最近学的ts基础语法笔记已记录完毕,后续会对进阶的知识作补充。