随着前端技术的更新迭代,TS已经算是很耳熟目染了,也能发现很多技术栈都用到了TS来进行开发,以下主要是针对刚开始初学TS需要掌握的内容
强类型与弱类型
强类型:
不允许有随意的隐式类型转化,例如传入的参数数据格式必须保持一致,否则会直接报语法错误
(优势,会在语法阶段直接爆出错误,代码更加智能,编码准确,重构定位问题,减少一步数据类型判断)
弱类型:
允许有隐式类型转换发生,如果传入参数不一致的情况,不会发生语法错误
(存在的问题:错误不能在语法层面直接报错,会发生类型转换,使得函数方法改变,数据类型不一致)
静态类型和动态类型
静态类型:
规定刚开始赋变量值后,不能对数据类型进行修改
动态类型:
赋值后是可以对变量的类型进行修改的
Javascript自身类型系统的问题
类同于弱类型和动态类型的问题
Flow静态类型检查
可以通过引入flow来对我们代码类型进行报错检测
步骤:
- 在项目代码中安装flow-bin用来检测我们代码的数据类型是否一致
- 使用过程中需要通过@flow来引入
- 特殊格式是无法通过vscode的自主语法校验的,需要关掉语法
//@flow
function sum (a:Number, b:Number) {
return a+b
}
// sum(100, 100)
sum('100', '100') -----开启flow检测会会直接报数据类型不一致的错误
Flow的使用更多是在代码书写阶段进行数据类型校验的,那么在编译阶段就需要将添加的flow移除掉,此处有两种方法可以工具化帮助我们移除
- 使用flow自带的工具flow-remove-types进行转化
- 使用babel工具,yarn add @babel/core @babel/cli @babel/proset-flow来进行文件的转化
Flow的原始类型
const a: string = 'football'
const b: number = 123
const c:boolean = true
const d: null = null
const e: void = undefined
-------数组类型
const arr1: Array<number> = [1,2,3]
const arr2: number[] = [1,2,3]
-------对象类型
const obj1: {foo:string,bar:number} = {foo:'string',bar:123}
const obj2: {foo?:string,bar:number} = {bar:123}
-------函数类型
function foo() :number }{
return 100
//如果什么都不返回,就需要定义成void类型
}
-------maybe类型
const type: 'success'|'waring'|'allright' = 'success'
const b: StringOrNumber = 'string'
const gender: ?number = undefined
-------任意类型
function passMixed(value:mixed){} //保留强类型特性
function passAny(value:any){} //依旧是弱类型可以调用方法
---同样如果在使用dom元素获取的时候,都有api声明的一些数据类型限制
Typescript语言规范与基本应用
Object类型:不单单指的是传统{},还包括函数,数据,对象
const Object = function(){} //[] //{}
const Object:{foo:number,bar:string} = {foo:123,bar:'string'}
Array类型:
const arr: Array<Number> = [1,2,3]
const arr: number[] = [1,2,3]
//来限制传入的参数为数组结构的参数
function sum (...args:number[]) {
return args.reduce((pre,current) => pre+current,0)
}
元组类型:固定长度来返回内容
const tuple: [number,string] = [18,'string']
const [age,name] = tuple
Object.entries({
foo:123-----键值数组就是用元组表示的
})
//其中包括react中使用的usestatue就是元组返回结果
枚举类型:
enum PostStatus {
//如若不赋值,直接从1开始数字累加,也可以是字符串默认值,不过需要每一个都定义
Draft = 1,
Unpublished = 2,
Published = 3
}
//最后转化会出现双线数据定义,可以通过const变量来移除
const post = {
status: PostStatus.Draft
}
函数类型:
...rest来接受任意参数的接收值
function func(a:number,b:number=10,...rest:number[]):string {
return 'string'
}
func(10,20)
任意类型:
function stringify(value:any){
return JSON.stringify(value)
}
//any可以用来接收任意类型参数,一般不用存在安全性,但是如果兼容老代码可以使用
类型断言:类型转化是在执行过程发生,但是类型断言只存在于编译过程
const res = nums.find(i => i>0)
const num1 = res as number
const num2 = <number>res //JSX下不能使用,会被当作标签
接口
是Typescript中用来约束对象结构的,在编译之后并没有接口相关的代码,没有实际意义
export {}
interface Post {
title: String
content: String
subtitle ?: String ---用来表示可有可无
readonly summary: String ---用来标识只读成员
}
function printPost (post) {
console.log(post.title)
console.log(post.content)
}
printPost({
title:'Hello worlds' ,
content: 'A javascript superset'
})
//定义不确定性键值对成员
interface Cache {
[prop: String]: String
}
const cache: Cache = []
cache.foo = 'value'
TypeScript类的基本使用
不同于JS的类使用,TS类中变量定义之后需要对其进行提前声明
export {}
class Person {
name: String
age: Number
constructor(name:String,age:Number) {
this.name = name
this.age = age
}
sayHi (msg: String):void {
console.log(` I am ${this.name}, ${msg}`)
}
}
类的修饰符
一般有三种修饰
class Person {
public name: String ---公共成员对象
private age:Number ---私有成员对象,外部不能够进行访问,只能在对象内部访问
protected gender: boolean
---保护对象,只允许在此类中访问定义的成员
}
class Student extends Person {
private cosntructor (name: String, age:Number){
super(name,age)
console.log(this.gender) ---是可以进行访问的
}
static create (name: string,age:number){
return new Student(name,age)
}
}
//私有继承类之后,外部无法正常调用new来构造
const Jack = Student.creat('jack', 18)
类和接口
可以帮助我们定义不同类之间相同的公共属性
export {}
interface Eat {
eat(food:String):void
}
interface Run {
run(distance:Number):void
}
class Person implements Eat, Run{
eat(food:String):void {
console.log(`人类进食 ${food}`, )
}
run(distance:Number):void {
console.log(`直立行走 ${distance}}`, )
}
}
class Animal implements Eat, Run {
eat(food:String):void {
console.log(`动物咀嚼 ${food}`, )
}
run(distance:Number):void {
console.log(`爬行动物 ${distance}}`, )
}
}
抽象类的实现
如果定义了抽象类,就不可以new构造,只能通过子类来继承
export {}
abstract class Animal {
eat (food: string): void {
console.log(`动物吃: ${food}`)
}
abstract run(distance:number):void
}
class Dog extends Animal {
run(distance:number):void {
console.log(`爬行动物: ${distance}`)
}
}
const dog = new Dog()
dog.eat('骨头')
dog.run(100)
泛型
当我们定义不确定类型参数的时候,为了避免冗余,可以通过泛型来定义不同数据类型
export{}
function createNumberArray(length:number,value:number):number[]{
const arr = Array<number>(length).fill(value)
return arr
}
function createStringArray(length:number,value:string):string[]{
const arr = Array<string>(length).fill(value)
return arr
}
------------为避免以上两种情况的冗余,我们通过泛型来实现
function createArray<T>(length:number,value:T):T[]{
const arr = Array<T>(length).fill(value)
return arr
}
const res = createArray<string>(3,'foo')
类型声明
对于一些引入的第三方模块,可能没有对象的类型声明
- 添加相应的types声明模块@types/lodash
- 手动添加
declare function camelCase (input: string): string