一篇文章带你了解Typescript那些事儿
前言
最近小凌在维护前同事写的代码时,因为旧代码
缺少注释常常不知道该输入什么类型。心想着,如果一开始就用Typescript去设计代码,那么后续代码可维护性
将会大大提高。
Typescript基于JavaScript之上的编程语言
它解决了JavaScript自身类型系统
的不足。
为什么要使用TypeScript
JavaScript根本没有任何的类型限制,用一个词来形容就是“任性”
。
这样一来就缺失了类型的可靠性。在使用一个变量时我们总要担心它是不是我们想要的类型。这样一来这个语言给人带来的感觉就是“不靠谱”
。
举个例子:
因为没有参数限制,原来需要输入两个number
类型参数的函数,在输入string
格式后功能就完全发生了改变。
可能在注释时认真,看的认真也许就不会有问题。但是俗话说的好"君子约定有隐患,强制要求有保障"
,而使用Typescript就可以完全解决这个问题,大大提高了代码的可靠程度
。
安装与配置
安装
使用npm
或者yarn
安装
npm
npm init
npm install -g typescript
yarn
yarn init
yarn add typescript
当module
中存在相关js包时说明安装成功。
配置
初始化配置
yarn tsc init
当根目录下出现tsconfig.json
时说明初始化配置成功。
以下是重要配置的解释:
严格模式包括:
规则 | 解释 |
---|---|
noImplicitAny | 不允许变量或者函数参数具有隐式any类型 |
noImplicitThis | 不允许this上下文隐式定义 |
strictNullChecks | 不允许出现null或者undefined的可能性 |
strictPropertyInitialization | 验证构造函数内部初始化前后已定义的属性 |
strictFunctionTypes | 对函数参数进行严格逆变比较 |
类型
基础类型
Typescript的基础类型包括:
数据类型 | 关键字 |
---|---|
任意类型 | any |
数字类型 | number |
字符串类型 | string |
布尔类型 | boolean |
数组类型 | 无 |
元组 | 无 |
枚举 | enum |
void | void |
null | null |
undefined | undefined |
never | never |
Object类型
Typescript中的Object类型
并不单只对象类型,而是泛指所有的非原始类型
也就是 对象
、数组
、元素
。
// 报错 “sex”不在类型“{ name: string; age: number; }”中。
const foo: {name:string,age:number} = {name:"铁子",age:18,sex:'男'}
数组类型
声明数组的方式有两种
第一种是使用 Array
泛型
第二种方式就是用元素类型加方括号的形式声明一个数组类型
const arr1:Array<number> = [1,2,3]
const arr2:number[] = [1,2,3]
元组类型
元组类型
是一种特殊的数据结构,就是明确元素数量和每个元素类型的数组。
const tuple:[number,string] = [18,'lwh']
一般用来一个函数当中去返回多个返回值,比如在react useState() 和ES2017中提供的 Object.entries(获取一个对象当中的键值数组),他的返回参数就是一个元组。
枚举类型
元组类型
用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。
enum typeDict {
// 1 = '视频' // 枚举成员不能具有数值名。
video = '视频',
mp3 = '音频',
link = '外链'
}
const course = {
title:"喜马拉雅课程A",
content:"学了都说好",
type: typeDict.video
// video 视频 mp3 音频 link 外链
}
函数类型
当我们需要一个可选参数时我们也可以使用?
的形式。
如果我们需要给参数进行默认值设置可以参考ES6的默认参数
。
如果我们不确定参数个数,我们也可以参考ES6的rest操作符
。
任意类型any
由于JavaScript为弱类型的关系,它本身很多方法接收弱类型的参数。因为Typescript是基于JavaScript之上的,我们在使用过程中难免需要一个变量接收任意类型
的参数。
注意:any
在JavaScript中主要用来兼容
老的代码。
类型的隐式判断
在Typescript当中,如果我们没有明确通过类型注解去标记一个变量的类型,那typescript会根据你使用的状况去推断你的类型。
如果我们声明变量时我们并没有给它赋值,那么Typescript可以把他隐式推断为any
,之后我们可以将其赋值为任意的值。
类型的断言
在某些特殊的情况下Typescript不能推断
出某些变量的具体类型,而我们作为开发者,我们明确程序的执行状况明确知道变量是什么类型的。
查看以上代码我们可以知道上述代码的find可能找到的是undefined
或是number
,根据程序具体逻辑我们可以知道返回的res一定是一个number
类型。
实现断言的方式有两种:
第一种是使用 as
(推荐第一种)。
第二种是在变量使用尖括号的形式 (这一种会和jsx
的标签冲突)。
// 是一个明确接口返回的数字类型的数组
const nums = [111,222,111]
const res = nums.find(i => i > 1000)
// 对象可能未定义
// let square:number = res + res
// as 实现
const numas = res as number
const numasSum:number = numas * numas
// 尖括号方式实现
const numjian:number = <number>res
const numJianSum = numjian * numjian
类与接口
接口
接口
,可以理解为一种规范
或者是一种契约
。它是一种抽象
的概念,它可以用来约定我们对象的结构。我们要使用一个接口就必须要遵循
这个接口的全部约定
。
比如说我们需要实现一个打印课程信息的方法,需要必须的参数title
、content
和pic
,若形参实现了接口
那么我们的实参必须要有接口
中的属性。
接口补充
对于接口中的成员还有一些特殊的用法。
// 课程接口
interface Course{
title:string;
remark:string;
pic:string;
workName?:string; // 可选成员
readonly price:number; // 只读成员
}
我们首先来看可选成员
,当我们对象当中的一个成员是可有可无的,一般课程的作业是可有无的
。那么我们可以通过workName
变量名后面的问号?
来表示可选成员。 就等于标记workName
的类型为string
或undefined
。
然后我们来看只读成员
,一般我们课程的价格
是不允许外界设置的,那么我们就在价格变量前面添加一个 readonly
。属性只能再初始化时设置一次之后就无法修改
。
最后来看动态成员
的用法,我们接口再定义的时候不知道会有那些具体的成员。我们就可以使用动态成员
的方式。只不过我们这边动态成员
的类型是string
,若赋值其他类型则会报错。
类 (编程中重要的概念)
类可以说是面向对象
编程中最重要的概念,关于类的作用我们这边来简单描述一下,主要是描述一类事务的抽象特征
。
在ES6
之前,实现类的方式是函数+原型
模拟实现类
。
ES6
开始JavaScript就有了专门的class
。
而Typescript对与ES6提供的类
之外还进行了额外的拓展
。
声明一个类
:
class Person {
name: string; // init name
public readonly age: number; // = 15
protected gender: boolean; //
constructor(name:string,age:number){
this.name = name
this.age = age
this.gender = false
}
/**
* 说一句话
* @param msg 信息
*/
sayHi(msg:string):void{
console.log(msg);
}
}
我们声明一个类
,并建立一个构造函数
,在这里我们依然可以对构造函数
的参数进行类型指定类型。
值得一提的是,在Typescript中我们类
的属性必须
要有初始值
,我们可以在声明
时赋值或者在构造函数
中赋值即可。
访问修饰符
接下来我们来看访问修饰符
,我们在之前声明的类中稍加修饰,其实其中的变量
和方法
都可以加访问修饰符
。
首先我们来看private
,使用private
修饰的成员只能在类内部使用
,在外部调用时就会报错,以下代码我们通过private
修饰age
属性在类实例化的时候我们就无法访问
到内部的age
变量。
我们可以使用public
来修饰类中的成员,使其可以公有访问
,不过Typescript默认
的成员修饰符就是public
。
还有一个叫protected
(受保护的) 的修饰符,我们可以新声明一个成员去使用它,我们发现在对象实例的时候依然无法使用protected
修饰的成员,它主要是用来被子类所使用
的。我们可以声明一个student
类来继承person
类,我们可以发现在student类内部是可以使用gender
成员的。
总结就是:
public
公开的,都可以访问( 默认的修饰符)。
private
私有的,只允许在类的内部使用。
protected
受保护的,只有子类和自己可以使用。
只读属性
除了使用访问修饰符来控制我们的访问级别,我们还可以通过readonly
的关键词来把我们的成员设置成只读的
。
类与接口
类
可以通过implements
关键字来实现接口
。
以上是实现的两个类,猫
和狗
,他们都有同名的方法,但实现的方式不一样。这个时候我们就可以理解为他们实现了同样的接口也就是协议
。
有同学就要说了,我们只要有一个同样的动物父类不就行了么?但世界上的动物并不是同样的进食方式和运动方式,我们需要有一个约束
来使其必须有该方式并且有自己的实现方式。
抽象类
抽象类
和接口
类似,用来去约束子类当中必须要有某些成员,但不同的是抽象类
可以包含一些具体的实现
而接口只能是一个成员的抽象它不包含具体的实现
。
// 抽象类只可继承
abstract class Animal {
eat(): void{
console.log('可以吃')
}
abstract run() :void; // 抽象方法必须实现
}
class Dog extends Animal{
run(): void {
throw new Error("Method not implemented.")
}
}
let dog = new Dog();
dog.eat(); // 直接调用抽象类的方法 可以吃
重写和重载
重写
// 重写
class Animal {
public eat() {
console.log("这是一个吃的方法")
}
}
class Dog extends Animal {
public eat() {
console.log("这是一个小狗吃的方法")
}
}
let dog: Dog = new Dog()
dog.eat()
发生在父类与子类
之间。
方法名
,参数列表
,返回类型
(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
。
访问修饰符
的限制一定要大于
被重写方法的访问修饰符(public
>protected
>private
)。
重载
在一个类中,同名的
方法如果有不同的参数列表
(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载
。
泛型
泛型
,就是指我们在定义函数接口或者类的时候我们没有定义具体的类型,等到我们使用的时候
再去指定具体类型的这种特征
。
泛型
的作用主要是极大的复用
我们的代码。
/**
* 创建列表
* @param length
* @param value
* @returns
*/
function crateList<T>(length:number,value:T):T[]{
const arr = Array<T>(length).fill(value)
return arr
}
const arrString = crateList<string>(3,'xx'); // ['xx','xx','xx']
const arrNumber = crateList<number>(3,15); // [15,15,15]
这里我们可以通过一个例子来体现我们泛型的作用。我们需要创建一个被填满数字的数组
,我们就需要上面方法的代码 因为Array
默认生成的any
类型的数组,我们需要通过<T>
指定它的类型,当我们要创建String
类型数组时我们就需要复制一便再去改变类型。
类型的声明
在实际的开发中我们难免会用到一些第三方的NPM模块
,这些NPM模块
不一定是用Typescript,所以也不一定有强类型
的规范。
比如我们下载比较流行的lodash
模块,这个模块呢提供了比较多的函数。我们调用camelCase
这个函数,这个函数的作用就是将我们的字符串
转换为驼峰格式
。参数为string
返回也是string
当我们调用它的时候并没有什么类型提示。
我们可以npm通过安装对应的类型声明
yarn add @types/lodash
安装完成后就会有相应的类型错误
提示了:
中文提示安装
Typescript是支持多语言
化的,默认会根据你的操作系统和开发工具的语言错误信息。
我们可以通过 yarn tsc --locale zh-CN 来使其控制台支持中文的提示
yarn tsc --locale zh-CN
对于编译器
的提示我们可以使用 文件 =》首选项 =》 typeScript locale =》 设置为 zh-CN
即可
最后要说的
随着最后知识点的讲完我们今天的分享也到了尾声。纸上得来终觉浅,相信大家在实际运用中一定会有更深刻的见解。在后续使用的发现也会在这篇文章进行更新,欢迎大家收藏
和关注
。
以下是项目地址:ts项目地址
转载自:https://juejin.cn/post/7045710643390857224