许小墨のBlog —— 菜鸡博客直通车
系列文章完整版,配图更多,CSDN博文图片需要手动上传,因此文章配图较少,看不懂的可以去菜鸡博客参考一下配图!
–
TypeScript是由微软开发的一款开源的编程语言。
TypeScript是JavaScript的超集,遵循最新的es6、es5规范。TypeScript扩展了JavaScript的语法。
TypeScript更像后端java、C#这样的面向对象语言,可以让js开发大型企业项目。
谷歌也在大力支持TypeScript的推广,谷歌的angular2.x+就是基于TypeScript语法。
最新的vue、React也可以集成TypeScript。
nodeJs矿建Nestjs、midway中用的就是TypeScript语法。
简单来说,ts就是有严格的类型显示的js。
因为js是弱类型语言,写出来的代码不够严谨,用ts写来约束类型,当类型不对的时候,ts会报错,代码更严谨。
ts无法独立运行,必须将ts编译为js才能使用,编译工具叫typescript。
下载安装:
npm i typescript -g
测试:
tsc -v
编译命令:
tsc ts文件名
tsc 被编译的文件 --outFile 编译后的文件路径
为了方便我们使用ts开发,通常会使用ts的监视命令,当ts文件发生变化时,自动编译生成js文件,不用很频繁的对ts进行编译。
监视命令步骤如下:
初始ts - 生成ts的配置文件
tsc --init
修改配置文件
"outDir": "./js", // 出口文件夹
"rootDir": "./ts", // 入口文件夹
"module": "ES6", // 选择模块化标准
"target": "es5", // 目标js版本
执行监视编译命令
tsc -w
let 变量名:number = 值
let 变量名:boolean = true/false
let 变量名:string = ''
let 变量名:类型[] = [...]
let 变量名:Array<类型> = [...]
上面的类型,表示数组中存放的数据的类型
ts中的元组,在js中表示为多种类型数据组成的数组。
let 变量名: [类型1, 类型2] = [类型1对应的数据, 类型2对应的数据]
注意:元组类型在定义的时候就规定了长度,且顺序必须对应。
枚举类型表示现有的几个数据当中,必须选择其中一个。
定义枚举类型:
enum 类型名称 {指定的多个数据, ...}
定义变量为这个枚举类型:
let 变量名: 枚举类型名称 = 类型.数据
例:
enum Color {Red, Green, Blue}
let a: Color = Color.Red
console.log(a); // 0
默认获取到的是数字,如果要获取自定义的其他类型数,需要在定义枚举类型的时候,给每个数据赋值。
例:
enum Color {Red = 'red', Green = 'green', Blue = 'blue'}
let a: Color = Color.Red
console.log(a); // red
如果有些数据比较复杂,我们实在无力定义这个类型的话,可以使用任意类型,但要注意,任意类型对数据是没有约束性的。
let 变量名:any = 任意数据
当我们定义一个函数的返回值的时候,如果一个函数没有返回值,就可以使用void来表示。
function fn():void {
let a = 10
}
通常用于修饰参数和返回值,且通常会配合其他类型使用,因为一个变量定义为undefined类型后,今后只能是undefined,无法再赋值为其他类型的数据了。
function fn(b: number|undefined):number|undefined { // |表示或者的意思
let a = 10
return a
}
此时的函数在调用的时候,必须传入实参,实参必须是数字或undefined。
如果我们想表示这个参数可传可不传,就需要在参数后添加?
来表示
null表示没有的意思,通常用于将一个变量销毁。
let a:number|null = 10
a = null
never表示从来没有的意思,通常用于抛出错误的函数返回值,或有一个死循环的函数返回值。
function captureErr() :never {
throw new Error('错误信息')
}
function loop() :never {
while(true) {
}
}
Object类型表示对象类型,但这个对象不允许添加新属性,不允许修改数据,只能读取数据。
let a:Object = {
name: '张三'
}
有的变量可能会有多种类型,当进行某一个类型的运算时,因为有另一种可能,所以可能会报错。
此时就需要我们告诉程序,我断定这个变量确定是这个类型,放心进行运算即可。
变量 as 类型
例:
function fn(a:number|null):number {
// 断言 - 虽然这个变量可能会有其他类型,用来做数学运算会报错,但是我们可以断定这个变量肯定是数字,让程序放心计算
let b:number = a as number + 5
return b
}
ts中的类和es6的类写法差不多,但是属性和方法多了几个修饰符:
例:
class Person{
public type: string = '人类'
public static height:number = 180
public constructor() {
this.type = '人'
}
protected props() :number {
return 100
}
private money() {
return 20
}
static weight():number {
return 120
}
}
class Man extends Person{
}
let p = new Person()
let m = new Man()
在工作当中,通常会有组长写好大纲,组员根据大纲实现功能,组长是只提供大纲,不实现具体业务。
这里所指的大纲通常是抽象类。
抽象类也是一种类,只是通常没有具体的实现方法,他的出现只有一个目的 - 被继承。继承了抽象类后,必须实现其中定义好的没有实现具体业务的方法。
定义:
abstract class 类名{
可以有普通属性和方法
通常会有抽象方法 - 只有方法头,没有具体的实现
abstract 方法名称()
}
例:
abstract class Animal{
public name:string
constructor(name: string) {
this.name = name
}
abstract eat():void
}
class Dog extends Animal{
constructor(name: string) {
super(name)
}
eat():void {
console.log(this.name + '吃')
}
}
对象类型的键值对无法扩展,为了能让键值对进行扩展,ts提供了接口类型。
interface 接口名称 {
属性名: 类型;
属性名: 类型;
}
例:
interface obj {
name: string;
age: number
}
let man:obj = {
name: '张三',
age: 12
}
对象中的键值对顺序可以调整,属性名必须是经过接口定义过的,否则报错。
如果某个键值对要定义为可选项,需要在属性名后加?
interface obj {
name: string;
age?: number
}
函数的类型格式也可以使用接口做限制:
interface 函数类型 {
(参数1: 类型, 参数2: 类型) :返回值类型
}
例:
interface encrypt {
(key: string, value: number|string): string;
}
let md5:encrypt = function(key: string, value:number|string):string {
return key + value
}
md5('name', 'zhangsan')
要定义更灵活的数组类型和对象,可以使用可索引接口:
interface arr {
[index: number] :string
}
例:
数组
interface arr {
[index:number]:string
}
let a:arr = ['a', 'b', 'c']
对象
interface obj {
[index:string]:string
}
let b:obj = {
name: '张三',
age: '12'
}
一个接口可以继承一个接口,也可以让类实现接口的具体的定义:
interface Animal {
eat():void
}
// 接口继承接口
interface Person extends Animal{
work():void
}
// 类实现接口
class Man implements Person {
eat() {}
work(){}
}
既继承类,又实现接口,一起进行:
interface Animal{
eat():void
}
abstract class Person {
abstract work():void
}
class Man extends Person implements Animal {
public age:number
constructor(age:number) {
super()
this.age = age
}
work():void {
console.log('写代码');
}
eat() {
console.log('吃饭');
}
}
注意:必选先继承类,再实现接口
为了让函数或类中有统一的类型约束,ts提供了泛型。
函数泛型:
function 函数名<T>(value:T):T{
return value
}
代码中的T,表示一种类型,在调用的时候提前指定这是什么类型,后续代码中参数和返回值都必须是同样的类型:
function getData<T>(params:T):T {
return params
}
getData<number>(123)
getData<string>('abc')
泛型类:
class Person<T>{
eat(food:T) {
console.log(food)
}
sport(str:T):T {
return str
}
}
let p1:Person<string> = new Person()
p1.eat('12')
p1.sport('123')
跟es6的模块化一样。
在ts中不允许函数或类同名,但项目大了,难免有顾及不到的地方会重名,此时可以使用命名空间解决。
命名空间:一个假的空间,形成独立的作用域,不同作用域中可以有同名的类或方法。
namespace A {
export class Animal{
public name:string
constructor(name:string) {
this.name = name
}
}
export function fn() {
console.log(111);
}
}
namespace B {
export class Animal{
public name:string
constructor(name:string) {
this.name = name
}
}
export function fn(){
console.log(222);
}
}
let a1:A.Animal = new A.Animal('张三')
let a2:B.Animal = new B.Animal('李四')
console.log(a1);
console.log(a2);
A.fn()
B.fn()
命名空间是一个独立的区域,其中的数据必须经过导出。
本博文缺失大量图片,严重影响内容完整性以及阅读体验,完整内容请前往本人菜鸡博客——许小墨のBlog