一、为什么使用TypeScript
如果从类型安全的角度分析,js属于弱类型语言,即具有隐式转换的能力
'100' - 50 //50
'200' + 5 //2005
上面代码中,字符串与数字会根据操作符的不同,进行不同的隐式转换(字符串转数字||数字转字符串)
如果从类型检查的角度去分析,js属于动态类型语言,即声明的变量没有类型,变量的值有类型
let a = 'aaa'
a = 123
这里变量a是没有类型的,这里仅仅是存储了指向内存中某个存储位置的地址,至于这个存储空间存储什么类型的内容,变量a是不做限制的
js作为弱类型、动态类型的语言,会存在很多安全上的问题
1、某些错误只有在程序运行时才会爆出,例如:调用每个对象内不存在的方法
2、对于某些操作,会根据数据的类型不同,实现结果也不同,例如“+”操作符
在最初的设计中,之所有将js设计为弱类型语音,是因为js最初的目的是用来做一些表单验证,这里不需要太多复杂的业务逻辑,这种灵活的语言特性比较适合,目前随着js的应用场景日益复杂,node、小程序、单页应用等等,这种灵活的语言特性成为了它的缺点
TypeScript很好的解决了这个问题,它是js的超级,它除了自身新增的语言特性外,还可以将es2015编译为es5。
使用TS有如下好处
1、某些错误可以在程序的编译阶段爆出,而不是运行阶段
2、在vscode中会有自动提示的功能
3、便于大型项目的重构,例如想要给某个对象内的方法换一个名字,这里我们无需担心某个使用到改方法的地方没有改过来,如果没有改,在编译阶段就会报错了
4、减少不必要的类型判断,例如我们进行某些运算操作之前需要增加判断处理,使用TS则可以省略
二、TypeScript特性简介
1、类型声明
Object类型
const hello:object = {key: 'string'}
const fun:object = (data:string)=>console.log(data)
object类型可以是对象,可以是函数,也可以是数组
如果想仅仅是对象类型
const obj:{str: string, num: number} = {str: 'sss', num: 100}
数组类型
const arry: Array<number> = [1,23]
const arry2: number[] = [1,3,4]
元组类型:固定长度固定元素类型的数组
const arr3: [string, number] = ['222', 333]
枚举类型
enum status {
statusA,
statusB,
statusC
}
enum statusStr {
statusA = 'aaa',
statusB = 'bb'
}
const _obj = {
statu: status.statusA, // 0
statuB: status.statusB // 'bb'
}
函数声明
function fun1 (a: number, b: number):string {
return 'stirng'
}
const fun2:(a: number, b?: number | undefined) => string = function (a: number, b?: number):string {
return 'string'
}
任意类型
let anyType: any = 123
anyType = 'string'
anyType = null
2、类型断言
断定某一个变量是某一种类型,可以使用as关键字或者<>形式,<>不兼容jsx
const arr = [1, 2, 3]
let num = arr.find(i=>i>0);
const num1 = num as number
const num2 = <number>num
console.log(num1 * num1)
3、接口
约束对象的类型
interface Post {
name: string;
age?: number,
readonly sub: string
}
const post:Post = {
name: 'wss',
age: 200,
sub: '88888'
}
let s = post.sub
interface Catch {
[key: string]: string
}
const c: Catch = {
sss: '333',
ssb: '999'
}
4、类
class Person {
name: string
private age: number
protected gender: boolean
constructor (name: string, age: number) {
this.name = name
this.age= age
this.gender = true
}
syaHi (msg: string):string {
return `hello ${msg}`
}
}
class Student extends Person {
constructor (name:string, age: number) {
super(name, age)
console.log(this.gender)
}
}
const tom = new Person('tom', 18)
console.log(tom.name)
const xiaoming = new Student('wwww', 21)
xiaoming.syaHi('nihao')
class Worker extends Person {
readonly gender: boolean
private constructor (name: string, age: number) {
super(name, age)
this.gender = false
}
static create (name: string, age: number) {
return new Worker(name, age)
}
}
const worker = Worker.create('eee', 39)
worker.gender
与es2015相比,增加了属性的类型限制,增加了private、plubic、protected修饰符
其中,private与protected都是限制外部不能访问,protected子类可继承,private子类不可继承
constructor也可增加修饰符,如果设为private,不能使用new操作符
类与接口
声明了某个类应该具有哪些方法,不包含具体实现
interface EatAndRun {
eat (food: string): void
run (distance: number): void
}
interface Eat {
eat (food: string): void
}
interface Run {
run (distance: Number): void
}
class Person implements Eat, Run{
eat (food: string): void {
}
run (distance: number): void {
}
}
class Animate implements EatAndRun {
eat (food: string): void {
}
run (distance: number): void {
}
}
抽象类
与接口的区别时有具体的实现逻辑
abstract class Animate {
eat (food: string) {
console.log(food)
}
abstract run (distance: number): void
}
class Dog extends Animate {
run (distance: number) {
console.log('hhhh', distance)
}
}
const dog = new Dog()
dog.eat('foooo')
dog.run(300)
泛型
函数在刚开始声明的时候,入参类型不确定,根据类型的不同,返回对应的类型,这时可以使用泛型
function createArry<T> (length: number, value: T): T[] {
const arr = Array<T>(length).fill(value)
return arr
}
createArry(3, 'eee')