Typescript是JavaScript的一个超集,除了有JavaScipt的特性外,同时拥有自己的静态类型,且不能直接在浏览器中运行,需要先编译成Javascript代码,才能运行。此外,TypeSciprt还拥有自己的其他一些特性。
静态类型
我们都知道,JavaScript是动态类型,TypeScript是静态类型。
那什么是动态类型?什么是静态类型呢?
动态类型指的是在代码运行的时候数据类型才会确定,数据类型绑定是代码运行的时候确定的。
静态类型指的是代码运行之前就做的数据类型检查,运行前数据类型就已经确定了。
静态类型分为基础类型和对象类型,和JavaScript类似,基础类型包括String、Number、Boolean、Symbol、Undefined、Null。对象类型包括Object, Array, Class类,函数类型等。
在JavaScipt中,这种写法是允许的。
let a = 5;
a = "5";
在TypeScript中:
let b:number = 5;
b = "5"; //会报错,因为不是同类型
//其他基本类型和数组类型示例
let str:string = "test"
let bool:boolean = true
let q:undefined = undefined
let w:null = null
let arr:number[] = [1,2,4]
let arr:Array<number> = [1,2,3]
这里说一下元组,元组是用于约束数组每一项的类型
//定义一个数组
const arr: number[] = [1, 2, 3]
//以上方式只能限制每一项元素只能是number,当我们希望我们数组的元素可能是string,
//也可能是number时则需要元组
//限制arr1的元素arr1[0]是string arr[1]是number arr[2]是string
const arr1: [string, number, string] = ['1', 2, '3']
Any类型
在定义变量类型的时候可以设置为Any类型即任意类型
let m: any;
m = 5;
m = "5";
let n; //此时Ts会将n认为是任意类型,等价于let n: any
类型注解
当我们在写TypeScript时会显示的声明一个变量的类型,这种操作即类型注解,告诉Ts变量是什么类型
const m: string = "1"; //显示告诉ts m变量是string类型
类型推论
TypeScript会自动尝试分析变量的类型
let m = 3;
m = "5"; //此时,会报错。因为ts已经分析出m为number类型
当我们我们在写TypeScipt时应该保证每个变量或属性都应该有唯一的类型!
函数相关类型
虽然有时候TypeScript能根据入参推断出函数返回值的类型,但为了避免问题,最好还是定义函数的返回值类型
函数相关类型有number、void、never等
never表示永远不会结束
function fun(): never {
throw new Error("error") ;
}
函数的定义
//函数声明的方式
function add(x: number, y: number): number {
return x + y;
}
//函数表达式
let myAdd =
function(x: number, y: number): number {
return x + y;
}
值得注意的是,其实myAdd函数并没有手动的添加类型,是由右边的添加了类型的匿名函数通过赋值进行类型推断得到的类型,如果真的需要对myAdd进行类型定义,应该使用下面的方式:
let myAdd: (x: number, y: number) => number =
function(x: number, y: number): number {
return x + y
}
在定义函数时,函数的参数可以是可选的,需要注意的,可选参数需要跟在必选参数的后面,可选参数后面不能再跟必选参数!!!
//正确
function getName(firstName: string, secondName?: string): string {
return secondName? `${firstName}${secondName}` : `${firstName}`
}
//错误
function getName(firstName?: string, secondName: string): string {
return firstName? `${firstName}${secondName}` : `${secondName}`
}
函数参数可以添加默认值
function getName(firstName: string = "Li", secondName: string): string {
return `${firstName}${secondName}`
}
接口Interface
接口可以允许我们约束一个对象,这个对象具有什么属性,且属性值是什么类型。
interface Person {
name: string
age: number
}
function getName(person: Person) {
return person.name
}
let person = {name: "LiLi", age: 18, sex: "Female"}
getName(person) //return LiLi
上面这个例子定义了一个Person对象的类型,具有name和age属性,且属性值分别为string类型和number类型
但需要注意的是,TypeScript中并不是像其他语言一样,实现了Person这个接口,只会会关注传入参数是否满足Person这个接口定义的条件,满足则通过。
可选属性
有些属性可能在某些场景下并不是必须的,这样可以在使用这个对象时只传入必须的属性即可。
interface Person {
name: string
age?: number
}
let p: Person = {name: "LiXiaoNi"} //可以检验通过
正是这种不确定性的属性,可以使用自定义属性和自定义属性值的方式,如下:我们自定义了一个Person类型,具有string类型的属性和属性值
interface Person {
[property: string]: string
}
let p: Person = {name: "LiLi"};
只读属性readonly
interface Person{
readonly name: string
}
const p1: Person = {name: "Lili"}
p1.name = "LiXiao" //不允许!!
额外属性检查
当我们将对象字面量作为变量赋值或者参数传递的时候,对象字面量就会经过额外属性的检查,若有多的属性是不允许的。
interface Person {
name: string
}
function getName(person: Person) {
return person.name
}
//1.作为参数传递
getName({name: "LiLi", age: 18}) //会报错,因为多了age属性
//2.作为对象赋值
let person: Person = {name: "LiLi", age: 18}
当我们想绕过这样额外属性的检查,可以使用类型断言或者定义属性,那什么是类型断言呢?让我们接着往下看。对了,其实我们在编写代码时往往不应该去绕过检查,而是应该去检查我们接口定义!
//类型断言的方式 as
getName({name: "LiLi", age: 18} as Person)
//定义属性的方式即添加一个age属性
//将接口Person重新定义为下面的格式
interface Person {
name: string
age?: number
}
函数类型
在接口Interface的定义中,我们通常还会定义函数
interface Fun1{
(param: string): string
}
let fun1: Fun1 = (param: string) => {
return param
}
fun1("111")