typescript
为什么会出现typescript
js是动态数据类型,不能进行数据类型的校验,导致我们接触别人的代码的时候很有可能不知道这一行代码是什么意思,需要传递什么样的参数,导致写代码的困难以及bug的增加。
所以出现了typescript这种超级JavaScript,这种非动态数据类型的语言--》 静态类型的语言。
来解决这一现状,达到正确性,可维护性。
什么是typescript?
如上可以知道,ts是超级js,是静态类型的,是可以约定数据类型的一种语言。
它最明显,最核心的作用,也是约定数据类型。
正因为是“约定”,所以,我们写数据的时候,就必须把数据的类型给带上,并且匹配正确,如果不正确,就会报错!
typescript如何使用?
基础使用
1.常见的类型使用
string,number,同一类型的数组,数组里面有不同的类型
let name: string = 'name'
let age:number = 12
let happy:boolean = true
let address: string[] = ['chengdu','beijing']
let likes: [string,number] = ['hahaha', 12]
2.undefined与null的类型使用
let student: undefined = undefined
let student: null = null
let student: string = undefined
let student: string = null
3.万金油类型:any
let studeng: any = 'haha'
let studeng: any = 1212
let studeng: any = [1,2,3]
let studeng: any = [1,'haha',undefined]
let studeng: any = undefined
let studeng: any = null
let studeng: any = {}
4.联合类型 union types
如果我们不确定这个类型是什么,但是可以锁定是哪几个类型,可以使用联合类型,来表明既可以是x类型,又可以是y类型!
let haha: string | number = 12
let haha: string | number = 'hahha'
// 既可以是number类型,又可以是string类型
接口使用
接口的基本使用方法
interface Person{
readonly id: number;
name: string;
age: number;
address?: string[];
}
let rose: Person={
id: 1,
name:'rose',
age:19,
address:['chengdu','shanghai']
}
接口的使用如上述代码,并且还使用到了readonly 与 ? :
readonly : 如果我们有一个属性,我们不希望被修改,是只读的,我们可以使用readonly来约束它! 我们试图改变这个值,就会报错!
? :如果我们有一个值,是可用可不用的,那么我们可以在这个属性后面加上一个?。
哪些常见可以使用到接口?
我们的参数x,y,z是必须是number类型的(z参数使用了?,所以z参数是可传可不传的),并且这个函数的返回值的类型也必须是number类型的。
function add(x: number, y: number, z?:number):number{
return x+y+z
}
const total = add(1,2,3)
const total = add(1,2)
我们的add2这个值,的类型是(x:number, y:number, z?:number),并且返回值是number,add2等于add。
这样写法的目的就是为了对标add方法,add2的参数类型以及返回值的类型与add方法是一致的。
let add2: (x:number, y:number, z?:number) => number = add
上面的写法感觉有点累赘,我们试一试刚刚学习的interface:
ISum 一般我们会在interface定义的东西前面加上一个I表明是interface定义的。
interface ISum {
(x:number, y:number, z?:number):number
}
let add2: ISum = add
如果我们的函数传递的参数是不太确定的,既可以是string类型的,又可以是number类型的,那么我们可以使用上面已经学习的联合类型!
as关键字可以把我们的类型,强制变成xx类型!
function getLength(input: string | number):number{
const str = input as string
}
Class类的使用
class的使用场景在哪里?我们学了这个东西有什么用?
react的组件就是用class写的哈!
1.Class基础的使用
class Animal {
readonly name: string;
constructor(name){
this.name = name
}
run(){
return `${this.name} is running!`
}
}
就比如在react里面,state我们就可以使用上readonly!
2.Class里面interface的继承
interface 的 implements 与 extends的 使用
- 我们类可以implements继承接口,继承了这个接口就必须实现这个接口里面写的方法!
- 我们类可以同时继承多个接口。implements
- 接口可以继承接口!extends
// 我们写了一个接口,这个接口实现了一个名为switchRadio的方法,并且这个方法要传递一个为布尔类型的参数trigger,并且没有返回值!
interface Radio{
switchRadio(trigger: boolean):void;
}
interface Battery {
checkBatteryStatus(): void;
}
interface RadioWithBattery extends Radio{
checkBatteryStatus(): void;
}
class Car implements Radio{
// Radio里面实现了这个switchRadio,我们必须实现这个方法!
switchRadio(trigger: boolean){
}
}
//可以继承多个接口!
class Car implements Radio, Battery{
// 每个接口里面实现的方法都必须实现了!
switchRadio(trigger: boolean){
}
checkBatteryStatus(){
}
}
枚举enum
默认情况我们的eunm,是数字,从0开始,以此往后。
但是不太好使用,为了更好的使用,我们往往给枚举里面的值进行一个字符串的赋值,让值的含义更贴合我们的业务,更好的进行一个逻辑的判断。
enum Direction {
Up = 'Up',
Down = 'Down',
Left = 'Left'
Right = 'Right'
}
if('Up' === Direction.Up){
}
范型 Generics
就像一个占位符,在使用的时候才动态的填入类型!
function echo<T>(echo: T):T{
return echo
}
function swap<T,U>(tuple:[T,U]):[U,T]{
return [tuple[1], tuple[0]]
}
function echoWithArr<T>(arg: T[]):T[]{
console.log(arg.length) // 数组有length的属性,是正确的哈!
return arg
}
//---------
function echoWithArr<T>(arg: T):T{
console.log(arg.length) // 此时会报错!
return arg
}
echoWithArr('hahhahahah')// 此时会报错!但是我们的string确实也是有length的属性的啊!怎么办呢?
//------------
interface IWithLength {
length: number;
}
function echoWithLength<T extends IWithLength>(arg:T):T{
console.log(arg.length)
return arg
}
echoWithArr('hahhahahah') // 此时不会报错了!
范型在类和接口中的使用
我们约定好Queue这个class里面的T,就是number
class Queue<T> {
private data=[];
push(item: T){
return this.data.push(item)
}
pop():T{
return this.data.shift()
}
}
const queue = new Queue<number>()
Type类型别名
type是interface的好兄弟!他们有着相似的使用场景,但是还是有些不一样的特点。
type的使用
- 如果我们需要制定默认值
- 如果我们的值只能为这几个默认值的其中一个
- 合并类型
const str: 'name' = 'name'
const num: 1 = 1
// 如果我们的值只能为这几个默认值的其中一个
type Directions = 'Up' | 'Down' | 'Left' | 'Right'
let own: Direction = 'Left'
// 交叉类型
interface IName{
name: string
}
type IPerson = IName & {age: number}
const person:IPerson = {
name:'rose',
age:18
}
如何选择type与interface
- 如果你想要使用extends和implements,你就要选择interface
- 如果你希望实现类型的默认值,交叉类型,你可以选择type
typescript的好处/坏处是什么?
好处:约定类型,解决类型不明确时候的不可维护性,提高代码的可维护性,可读性。
坏处:学习成本!