本文已参与「新人创作礼」活动,一起开启掘金创作之路。
什么是typescript
总所周知,js是一种动态语言(弱类型语言),变量在使用之前不用声明类型。 因此变量的类型随着程序运行可能发生变化。js的特点是非常灵活,但是随着程序的扩大,因为没有类型逐渐变得难以维护。还有js语言的一些怪癖,例如null、空字符串、NaN等奇怪判断。
ts有以下特点:
- ts是js的的超集。js语法是合法的ts。
- ts添加了关于如何使用不同类型值的规则。并且根据这些规则进行静态的类型检查
- ts需要编译成js,然后再使用
- ts结合编译器做到了类型提示、代码补全等功能
- ts可以和js共存,可以简单的把js项目逐步迁移到ts上
- ts拥有tsconfig.json配置,可以调整配置来确定项目类型检查的严格程度
常用类型
string表示字符串
const hello: string = 'hellp World'
number表示数字类型
const n: number = 1;
const f: number = 3.14;
boolean布尔类型
boolean类型实际上是true和false的联合类型(true|false)
const flag:boolean = true;
null和undefined
- null和undefined表示不存在或未初始化的值。 这两个类型的行为取决于ts配置中strictNullChecks是否开启
当strictNullChecks开启,ts会对null和undefined做出严格的检查,例如
// tsconfig.json
{
"compilerOptions": {
"strictNullChecks": true
},
}
let ObjectOrUndefined:undefined|{name:string}
// 这里会提示 对象可能为“未定义”。
ObjectOrUndefined.name
如果,strictNullChecks为false,例子中的ObjectOrUndefined.name就不会报错。建议打开strictNullChecks
- 非空断言
ts存在一种特殊的语法。可以在变量后面添加一个
!表示这个值不应该是undefined或null
let ObjectOrUndefined:undefined|{name:string}
bb!.name
当然,你也可以使用js中的可选链操作符?.来防止从undefined和null中取值的错误
let ObjectOrUndefined:undefined|{name:string}
bb?.name
void空值类型。可以用它表示没有任何返回值的函数
function hello():void{
console.log('hello world')
}
any
- 任意类型,当不希望ts的类型检查对某个特定的值报错的时候可以使用它。
- 当一个值的类型是any时,它可以被赋值为任何类型
- 尽量不要使用any,因为any没有进行类型检查,也就失去了ts的意义
let anyValue:any = 1;
anyValue = 'any'
// 这里赋值为字符串还能被调用,显然是错误的,由于是any,所以ts不会报错
anyValue();
anyValue(1,2,3)
// 没有初始化的变量也会被推论为any
// let anyValue: any
let anyVlaue
- 数组
有两种表示形式
Array<T>或者T[]
可以附加readonly修饰
const arr:number[]=[1,2,3]
const arr2:Array<number> = [1,2,3]
const arr3:(number|string)[] = [1,'q']
const readonlyArr:readonly string [] = ['a', 'b']
// 类型“readonly string[]”上不存在属性“push”。
readonlyArr.push('2')
const readonlyArr2:ReadonlyArray<string> = ['a', 'b']
// const readonlyArr2:ReadonlyArray<string> = ['a', 'b']
readonlyArr2.push('2')
- 元组 元组和数组非常的像。但是元组定义了数组中不同索引位置的元素是什么类型,它确切的知道包含多少个元素,每个特定位置是哪些类型
let tuple:[number, number, string] = [1,2,'3']
// 元组知道不同索引处值的类型
// const third: string
const third = tuple[2]
// 第一个索引处一定是number类型的,如果使用string类型就会报错
tuple = ['1', 2, '3']
元组剩余元素,类似于js中的剩余操作符,表示剩下的元素类型
const stringNumberBooleans:[string, number, ...boolean[]]=['a', 1, true]
只读元组
const readonlyTuple:readonly[number, number] = [1,2]
// 无法分配到 "0" ,因为它是只读属性。
readonlyTuple[0] = 3
unknown未知类型,它和any非常的像,但是它更加安全。因为unknown是未知的类型,因此不能访问它的任何数据
let anyValue:any
anyValue.aa
anyValue.bb
let unknownValue:unknown
// 类型“unknown”上不存在属性“aa”。
unknownValue.aa
bigint从ES2020开始,js拥有了表示大整数的类型bigint,由于是ES2020出现的,因此ts的配置target低于ES2020,bigint类型是不可用的
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020"
},
}
const n:bigint = 100n;
const n2:bigint = BigInt(1)
symboles6之后js拥有了符号类型,如果要在ts中正常使用需要在ts配置中lib要高于ES2015
// tsconfig.json
{
"compilerOptions": {
"lib": ["ES2015"]
},
}
const symbolValue1: symbol= Symbol('name')
const symbolValue2: symbol= Symbol('name')
// 不会报错
if(symbolValue1 === symbolValue2){
}
const firstName: unique symbol= Symbol('name')
const secondName: unique symbol= Symbol('name')
// 此条件将始终返回 "false",因为类型 "typeof firstName" 和 "typeof secondName" 没有重叠。
if(firstName === secondName){
}
接口和别名
- 接口
interface是命名对象类型的一种方式。
interface Animal{
name:string;
age:number
}
const tom:Animal = {
name:'tom',
age:2
}
- 可选属性
可以使用可选符号
?来表示对象中的某个属性是可选的
interface Animal{
name:string;
age?:number
}
// age可以不传
const tom:Animal = {
name:'tom',
}
- 只读属性
可以使用
readonly来说明某个属性是只读(不可赋值)的
interface Animal{
readonly name:string;
}
const tom:Animal = {
name:'tom',
}
// 无法分配到 "name" ,因为它是只读属性。
tom.name = 'jerry'
- 索引签名
如果我们不知道类型属性的所有名称,可以使用索引签名来描述可能的值的类型。
索引签名参数类型必须是string、number、symbol
interface Person{
name:string;
[other:string]:string;
}
当定义了索引签名之后,在类型中能够匹配上的属性类型,必须符合这个索引签名
interface Person2{
name:string;
// 这里会报错: 类型“number”的属性“age”不能赋给“string”索引类型“string”。
age:number;
[other:string]:string;
}
没有被索引类型匹配的属性则不受影响
interface Person2{
name:string;
age:number;
[other:number]:string;
}
// 这里name和age没有问题,其他属性是数字的,则对应的值必须是字符串
const p : Person2 = {
name:'1',
age:2,
2:'11'
}
由于js中对象以数字为key,实际上数字会被转成字符串作为key,所以索引类型为string会包含key为数字的情况
interface StringIndexType{
// 类型“number”的属性“0”不能赋给“string”索引类型“string”。
0:number;
[other:string]:string;
}
interface StringIndexType2{
[other:string]:string;
}
// 不能将类型“number”分配给类型“string”。
const obj : StringIndexType2 = {
2:1
}
const obj2 : StringIndexType2 = {
2:'1'
}
- 向现有类型添加属性
interface Base{
name:string;
age:number
}
interface Base{
address:string
}
// Base类型现在具有了name、age和address三个属性
const tom3:Base={
name:'jerry',
age:18,
address:'xxxx'
}
- 扩展类型
可以使用
extends关键字可以基于现有类型的基础上定义扩展类型,而不影响这个基础类型
interface Base{
name:string;
age:number
}
interface widthEmail extends Base{
email:string
}
const jerry:widthEmail={
name:'jerry',
age:18,
email:'xxx@xxx.com'
}
- 别名就是给一个类型取另一个名字
type Point = {
x:number,
y:number
}
type StringOrNumber = string|number
- 合并类型
使用
&运算符定义合并类型。
interface Colorful {
color: string;
}
interface Circle {
radius: number;
}
// Colorful和Circle生成了一个新的类型,同时具有color和radius属性
type ColorfulCircle = Colorful & Circle;
- 接口和别名的不同点
- interface是可以通过重复定义来添加属性的,type不能重复定义
- interface可以通过extends来扩展属性,type使用&来定义合并类型
- interface只能定义对象类型,type可以对原始类型重命名
参考链接:www.typescriptlang.org/docs/handbo… 思维导图:www.processon.com/view/link/6…