TypeScript学习笔记---基础篇

TypeScript 是由微软开发的自由和开源的编程语言,是 JavaScript 的一个超集,支持 ECMAScript 6 标准。其设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。

为什么学习typescript

目前主流的前端框架(react、vue)都使用ts的语法进行开发,typescript也是JavaScript的超集,相对于JavaScript来说更加严谨,
使用typescript可以编写出更加健壮的前端代码。

typescript无法直接在浏览器中执行,需要编译成JavaScript之后才能执行。

typescript代码无法在浏览器中直接执行

typescript静态类型

在JavaScript中

let a = 123;
a = '123'
js不会报错,代码可以正常执行(在JavaScript中变量的类型是动态类型,即变量的类型是可以改变的)

在typescript中

以下代码会报错,因为在typescript中,变量是静态类型,变量的类型不能改变(同时变量所属类型的方法跟随确定,例如定义了变量
为number类型,则该变量就会有number类型的方法和属性),vs-code执行示例:

ts文件中改变变量类型会提示错误

以下代码不会报错,因为在typescript中,变量是静态类型,变量重新赋值时,变量类型不改变,不会提示错误。vs-code执行示例如下:
let a = 123; 
// 完整的typescript写法为
let a:number = 123;
// 对a重新赋值时,只要类型不变,就不会提示错误,例如:
a = 456;

ts文件中改变变量值时,类型不变,不会提示错

typescript的数据类型

在typescript中希望各个变量、属性以及函数参数都有自己的变量类型
	// String 类型
	// 一个保存字符串的文本,类型声明为 string。可以发现类型声明可大写也可小写,后文同理。
	let str: string = 'abcd';
	
	// Boolen 类型
	// boolean是 true 或 false 的值
	// 所以 let isBool3: boolean = new Boolean(1) 就会编译报错,因为 new Boolean(1) 生成的是一个 Bool 对象。
	let isBool: boolean = false;
	
	// Number 类型
	let number: number = 10;
	
	// Any 类型
	// any 是默认的类型,其类型的变量允许任何类型的值。
	let any: any = 10;
	
	// Void 类型
	// JavaScript 没有空值 Void 的概念,在 TypeScirpt 中,可以用 void 表示没有任何返回值的函数。
	let sym1 = Symbol();
	let sym2 = Symbol("key"); // 可选的字符串key
  // 需要注意的是,Symbols是不可改变且唯一的。
	let sym2 = Symbol("key"); // 可选的字符串key
	let sym3 = Symbol("key");
	console.log(sym2 === sym3); // false, symbols是唯一的
  // 通过同样的方式生成两个symbol也是不同的,因为symbol是唯一的,因此sym2和sym3无论如何都不会相等
	
	// Symbol 类型
	// TypeScript中的Symbol的用法跟JavaScript一致,Symbols是不可改变且唯一的。
	function alertName(): void {
	    console.log('My name is changdong');
	}
	
	// Null 和 Undefined
	// TypeScript里,undefined和null两者各自有自己的类型分别叫做undefined和null。 
	// 和void相似,它们的本身的类型用处不是很大。
	let u: undefined = undefined;
	let n: null = null;
	> 	// 默认情况下null和undefined是所有类型的子类型。 就是说你可以把null和undefined赋值给number类型的变量。
	> 	let num: number; 	
	> 	num = 1; // 运行正确 	
	> 	num = undefined;    // 运行正确 	
	> 	num = null;    // 运行正确 	
	> 	// 然而,当你指定了--strictNullChecks标记,null和undefined只能赋值给void和它们各自。这能避免很多常见的问题。  	
	> 	// 启用 --strictNullChecks
	> 	//(启用strictNullChecks可以在项目中的tsconfig.json中配置{strictNullChecks: true},如下图所示) 	
	> 	let num: number; 	
	> 	num = 1;	// 运行正确 	
	> 	num = undefined;	// 运行错误 	
	> 	num = null;	// 运行错误
	> 	// 如果想传入一个string或null或undefined,你可以使用联合类型string | null | undefined。
	> 	// 启用 --strictNullChecks 	
	>	let num2: number | null | undefined; 	
	>	num2 = 1; // 运行正确 	
	>	num2 = undefined;    // 运行正确 	
	>	num2 = null;    // 运行正确

	
	// Never 类型
	// never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。
	// 这意味着声明为 never 类型的变量只能被 never 类型所赋值,在函数中它通常表现为抛出异常或无法执行到终止点(例如无限循环)。
	let a: never;
	let b: number;
	// a = 123; // 运行错误,数字类型不能转为 never 类型
	a = (() => { throw new Error('never')})(); // 运行正确,never 类型可以赋值给 never类型
	b = (()=>{ throw new Error('exception')})(); // 运行正确,never 类型可以赋值给 数字类型
	// 返回值为 never 的函数可以是抛出异常的情况
	function error(message: string): never {
	    throw new Error(message);
	}
	// 返回值为 never 的函数可以是无法被执行到的终止点的情况
	function loop(): never {
	    while (true) {}
	}
	// Object 类型
	// object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。
	// 使用object类型,就可以更好的表示像Object.create这样的API
	declare function create(o: object | null): void;
	create({ prop: 0 }); // OK
	create(null); // OK
	// create(42); // Error
	// create("string"); // Error
	// create(false); // Error
	// create(undefined); // Error
	
	// Array 类型
	// 数组是 Array 类型。然而,因为数组是一个集合,我们还需要指定在数组中的元素的类型。
	// 我们通过 Array or type[] 语法为数组内的元素指定类型
	let arr: number[] = [1, 2, 3, 4, 5];
	let arr2: Array<number> = [1, 2, 3, 4, 5];
	
	let arr3: string[] = ['1', '2', '3'];
	let arr4: Array<string> = ['1', '2', '3'];
	
	// Tuple 类型
	// 元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
	// 比如,你可以定义一对值分别为string和number类型的元组。
	let x: [string, number];
	x = ['hello', 10]; // OK
	// x = [10, 'hello']; // Error
	
	// Enums 类型
	// 枚举类型用于定义数值集合。
	// 列出所有可用值,一个枚举的默认初始值是0。你可以调整一开始的范围,后续的数值比前一个大 1 。
	enum People {Student = 3, Teacher, Doctor};
	let role1: People = People.Student;
	let role2: People = People.Teacher;
	let role3: People = People.Doctor;
	console.log(role1, role2, role3) // 3 4 5
	// 可以自己转换成js代码 之后打印一下People
启用 --strictNullChecks

启用 --strictNullChecks

typescript类型注解

在ts中,我们可以告诉ts,声明的变量是什么类型,叫做类型注解,例如:
	let a:number = 123let b:string = 'typescript'
如果没有告诉ts变量的类型,ts会自动判断变量的类型,叫做类型推断(如果ts可以判断变量类型,就不需要额外操纵,
但是如果ts不能判断变量类型,就需要使用类型注解,例如:)
	function getResult(a, b) { return a + b;}
	const result = getResult(1, 2)
	// 上述方法中的a、b、result,ts无法自动推断出其变量类型,就需要手动添加类型注解
在typescript中,我们也可以定义函数的返回值类型(对函数做类型注解),例如:
	function getNumber():number{}	// 指定函数返回值为number
	function getNumber():void{}		// 表示没有任何返回值的函数
	function getNumber():numberstring{}	// 指定函数返回值为number或者string
	// ... 可以定义多种类型
	// 解构类型参数的类型注解
	function getNumber({a, b}: {a:number, b:number}){return a + b}
	const result = getNumber({a: 1, b: 3}) // ts会自动判断result的类型为number

函数返回值类型校验提示错误
ts会自动判断result的类型为number

typescript类型注解的优势

使用typescript开发过程中,typescipt的类型检测可以提示代码编写过程的一些潜在错误,提升开发效率(在js中,以下代码只有在执行的时候才会提示错误)

TypeScript学习笔记---基础篇_第1张图片
TypeScript学习笔记---基础篇_第2张图片

使用typescript开发时,代码提示很友好(ts会对传入函数的数据属性进行提示)

ts会对传入函数的数据属性进行提示

类型声明

interface	// 可以声明一个类型(只能表示对象类型)
type		// 可以声明一个类型,可以表示对象类型和基本类型
在typescript中能用interface(接口)表示类型的时候就用interface,除此之外也可以使用类型变量(boolean、string等),使用如下:
interface Person {}
type Person = {}

typescript—interface

interface Person {
	readonly name: string,
	age?:number
}
// readonly表示name属性只读,不可修改; ?表示age属性可有可无
typescript中,声明变量形式传递参数时,函数会对参数进行校验,只要符合要求即可,如果传入方法中的是自变量对象时,
就会进行强校验,要求参数必须符合要求

TypeScript学习笔记---基础篇_第3张图片

如果传入的自变量参数不符合,可以使用如下写法
interface User {
	name: string,
	age?:number,
	[propName: string]: any
}
// [propName: string]: any 表示字符串类型的key,值可以为任何类型,这样就不会提示错误了

TypeScript学习笔记---基础篇_第4张图片

interface声明的接口,Class类可以使用 implements 关键字应用声明的接口,其他声明出来的接口可以使用 extends 关键字继承当前接口
interface还可以定义一个函数的类型接口,如下:
interface SayHello {
	(str:string):string
}
// 表示该接口函数接受一个字符串类型的参数,返回一个字符串类型的值,使用如下
const sayHello:SayHello = (str:string) => {return str}

typescript—类

跟JavaScript中一样,可以使用class 关键字声明一个类,类可以继承父类的属性和方法,也可以重写覆盖父类的方法,当我们重写父类的
方法之后需要调用父类的方法是,可以使用 super[父类方法] 的形式获取父类的方法和属性;
// class类的访问类型 public、private、protected
class Info {
	name: 'user',
	sayHi(){
		console.log('Hi')
	}
}
// public		允许对象的属性和方法在类的内部和外部被调用
// private		允许对象的属性和方法在类的内部被调用
// protected	允许对象的属性和方法在类的内部和继承的子类中使用 (new 关键字实例化的对象不能访问)
// 特殊:static	声明的属性和方法是挂在类上面,而不是示例上面
如果子类通过extends继承父类的属性和方法时,子类中也使用了constructor构造器,则需要在子类的构造器中使用super()方法,
调用父类的构造器,并将父类构造器需要的参数传递进去,如下:
class Person {
	// 传统写法
	public name: string;
	constructor (name: string){
		this.name = name
	}
	// 简化写法
	// constructor (public name: string){}
}
// 实例化操作 (实例化时,构造函数的constructor会在创建的时候被执行)
const person = new Person('w-wang')
console.log(person.name) // w-wang

// 使用extends继承时
class Man extends Person {
	constructor (public age: number){
		super('w-wang') // 调用父类的构造器,并传入参数
	}
}
const man = new Man(18)
console.log(man.age); // 18
console.log(man.name); // w-wang

类的应用

可以使用private设置私有变量,通过使用setter和getter实现访问和修改私有变量(参考vue),如下:
class Person {
	constructor (private _name:string){}
	get name(){
		return this._name
	}
	set name(){
		this._name = name
	}
}
const person = new Person('w-wang')
console.log(person.name); // w-wang 实际访问的是Person的get name方法
person.name = 'wei' // 实际访问的是Person的set name方法
// 附加:如果需要定一个不能修改的属性是,可以使用readonly,例如:public readonly name: string; 表示定义一个公开的只读的name属性
也可以根据类的特性,创建一个只能实例化一次的构造函数
class Demo {
	private static instance: Demo;
	constructor (){}
	static getInstance(){
		if(!this.instance){
			this.instance = new Demo()
		}
		return this.instance
	}
}
const demo1 = Demo.getInstance()
const demo2 = Demo.getInstance()
// demo1和demo2是相同的
备注:可以使用abstract 定义一个抽象类,定义一下公用的抽象方法,供其他的类继承,如下:
abstract class Area {
	abstract getArea():number; // 定义返回值为number类型
}
class Circle extends Area{
	getArea(){
		rentun 123
	}
}
class Square extends Area{
	getArea(){
		rentun 456
	}
}
// 其他的类

typescript基础语法学习结束,继续学习

你可能感兴趣的:(typescript,typescript,前端,编程语言,javascript)