本文章计划主要是学习typescript的基本知识总结,不涉及深入分析
typescript介绍
typescript是什么
TypeScript(简称:TS)是 JavaScript 的超集(JS 有的 TS 都有)。
TypeScript = Type + JavaScript(在 JS 基础之上,为 JS 添加了类型支持)。
TypeScript 是微软开发的开源编程语言,可以在任何运行 JavaScript 的地方运行。
typescript相对javascript优势
- 从编程语言的动静来区分,TypeScript 属于静态类型的编程语言,JS 属于动态类型的编程语言。
静态类型:编译期做类型检查; 动态类型:执行期做类型检查。 代码编译和代码执行的顺序:1 编译 2 执行。
-
程序中任何位置的代码都有代码提示,随时随地的安全感,增强了开发体验。
-
强大的类型系统提升了代码的可维护性,使得重构代码更加容易。
typescript初体验
typescript安装包
因为node.js不识别我们的ts,需要安装依赖进行转换
npm i -g typescript
验证是否安装成功:tsc –v(查看 typescript 的版本)
编译项目 tsc 文件名 (内部会把ts文件转换成为js文件)
执行 JS 代码:在终端中输入命令 node 转换的js文件。
简化运行 TS 的步骤 问题:每次修改代码后,都要重复执行两个命令,才能运行 TS 代码,太繁琐。
简化:使用 ts-node 包,直接在 Node.js 中执行 TS 代码。
安装命令:npm i -g ts-node(ts-node 包提供了 ts-node 命令)。
使用方式:ts-node ts文件。
解释:ts-node 命令在内部偷偷的将 TS -> JS,然后,再运行 JS 代码。
typescript常用类型
可以将 TS 中的常用基础类型细分为两类:1 JS 已有类型 2 TS 新增类型。
- JS 已有类型
1.原始类型:number/string/boolean/null/undefined/symbol。 2.对象类型:object(包括,数组、对象、函数等对象)。
- TS 新增类型
l 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any 等。
typescript原始类型
原始类型:number/string/boolean/null/undefined/symbol。
typescript对象类型
对象类型:object(包括,数组、对象、函数等对象)。
特点:对象类型,在 TS 中更加细化,每个具体的对象都有自己的类型语法。 一般使用interface声明具体属性类型,然后继承引用
interface Iprops {
type:string
children: Array<string>
}
let list :Iprops[]
数组类型
let list: string[] = ['1','2']
let newList: Array<string> = ['1','2']
let newList: (string | number)[] = ['1','2',3]
(竖线)在 TS 中叫做联合类型(由两个或多个其他类型组成的类型,表示可以是这些类型中的任意一种)。
函数类型 函数的类型实际上指的是:函数参数和返回值的类型。
为函数指定类型的两种方式: 1 单独指定参数、返回值的类型
function add (num1: number, num2:number) :number {
return num1+num2
}
2 同时指定参数、返回值的类型。
const add = (num1: number, num2:number) :number = number =>(num1: number, num2:number) {
return num1+num2
}
3 没有返回值
const add = (num1: number, num2:number) :void {
num1+num2
}
4.参数问题 (可传可不传)
const add = (num1?: number, num2?:number) :void {
num1+num2
}
注意:可选参数只能出现在参数列表的最后,也就是说可选参数后面不能再出现必选参数。
typescript类型别名
类型别名(自定义类型):为任意类型起别名。
使用场景:当同一类型(复杂)被多次使用时,可以通过类型别名,简化该类型的使用。
type Iprops = number
let list :Iprops = 1
typescript类型接口
当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的。
interface Iprops {
type:string
children: Array<string>
}
let list :Iprops[]
type和interface的对比
- 两者都可以用在对象定义,但是type还可以用在其他类型定义,而interface只能用于对象型数据
interface Iprops {
type:string
children: Array<string>
}
let list :Iprops[]
type Iprops {
type:string
children: Array<string>
}
let list :Iprops[]
type a: string | number
interface Dog { wang(); }
interface Cat { mao(); }
type P = Dog | Cat
// 具体定义数组每个位置的类型
type Pet = [Dog, P]
- 拓展的extend interface可以拓展extend,但是type不能
interface Name { name: string; }
interface User extends Name { age: number; }
type Name = { name: string; }
type User = Name & { age: number };
interface Name { name: string; }
type User = Name & { age: number; }
- type 语句中还可以使用 typeof 获取实例的 类型进行赋值
// 当你想获取一个变量的类型时
typeof let div = document.createElement('div');
type B = typeof div
- interface 能够声明合并
interface User { name: string, age: number }
interface User { sex: string }
/* User 接口为 { name: string age: number sex: string } */
- type 其他操作
typescript元组
确切地知道包含多少个元素,以及特定索引对应的类型 场景:在地图中,使用经纬度坐标来标记位置信息。
可以使用数组来记录坐标,那么,该数组中只有两个元素,并且这两个元素都是数值类型
let map: [number,number] =[123,12]
typescript类型推论
在 TS 中,某些没有明确指出类型的地方,TS 的类型推论机制会帮助提供类型。
换句话说:由于类型推论的存在,这些地方,类型注解可以省略不写!
发生类型推论的 2 种常见场景:1 声明变量并初始化时 2 决定函数返回值时
let name = 'kevin
function add(num1:number,num2: number) { return num1+num2 }
typescript类型断言
- 使用as实现类型断言
let alink = ducument.getElementById('link') as HTMLAnchorElement
- 使用 <> 语法
let alink = <HTMLAnchorElement>ducument.getElementById('link')
typescript字面量类型
使用模式:字面量类型配合联合类型一起使用。
使用场景:用来表示一组明确的可选值列表。
function changeDirection (direction: 'up' | 'right' | 'down' | 'left') {}
typescript枚举
枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值。
枚举:定义一组命名常量。它描述一个值,该值可以是这些命名常量中的一个。
enum direction {
up,
right,
down,
left
}
function changeDirection (direction: direction) {}
直接通过点(.)语法访问枚举的成员
注意:枚举成员是有值的,默认为:从 0 开始自增的数值。
enum direction {
up =10,
right=11,
down =12,
left =16
}
any 类型
原则:不推荐使用 any!这会让 TypeScript 变为 “AnyScript”(失去 TS 类型保护的优势)。
因为当值的类型为 any 时,可以对该值进行任意操作,并且不会有代码提示
除非临时使用 any 来“避免”书写很长、很复杂的类型!
其他隐式具有 any 类型的情况:1 声明变量不提供类型也不提供默认值 2 函数参数不加类型。
注意:因为不推荐使用 any,所以,这两种情况下都应该提供类型!
typescript高级类型
class 类
- 类继承的两种方式:1 extends(继承父类) 2 implements(实现接口)。
class animal {
move(){console.log('animal')}
}
class cat extend animal{
eat(){console.log('cat')}
}
1.通过 extend 关键字让 class 实现接口。 2.子类 cat 继承父类 Animal,则 Dog 的实例对象 dog 就同时具有了父类 Animal 和 子类 Dog 的所有属性和方法。
class singable {
sing()void
}
class person extend singable{
sing(){console.log('sing')}
}
1.通过 implements 关键字让 class 实现接口。
2.Person 类实现接口 Singable 意味着,Person 类中必须提供 Singable 接口中指定的所有方法和属性。
- 类成员可见性:可以使用 TS 来控制 class 的方法或属性对于 class 外的代码是否可见。
可见性修饰符包括:1 public(公有的) 2 protected(受保护的) 3 private(私有的)
static关键字, 用于定义类的数据成员(属性和方法)为静态的, 静态成员和方法可以直接通过类名调用。举例
class Dog {
// 属性
static color: string
static show() {
console.log(`我是一只${Dog.color}的狗`)
}
}
Dog.color = "白色"
Dog.show();
- public:表示公有的、公开的,公有成员可以被任何地方访问,默认可见性。可以直接省略
class animal {
public move(){console.log('animal')}
}
- protected:表示受保护的,仅对其声明所在类和子类中(非实例对象)可见。
class animal {
protected move(){console.log('animal')}
}
class cat extend animal{
eat(){
this.move()
console.log('cat')
}
}
- private:表示私有的,只在当前类中可见,对实例对象以及子类也是不可见的。
class animal {
private move(){
this.move()
console.log('animal')
}
}
class cat extend animal{
eat(){
this.move() //不行
console.log('cat')
}
}
类型兼容性
两种类型系统:1 Structural Type System(结构化类型系统) 2 Nominal Type System(标明类型系统)。
TS 采用的是结构化类型系统,也叫做 duck typing(鸭子类型),类型检查关注的是值所具有的形状。
也就是说,在结构类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型。
class animal {
name: string,
age: string
}
class animalBig {
name: string,
age: string
}
const A: animal = new animalBig()
1.Point 和 Point2D 是两个名称不同的类。
2.变量 p 的类型被显示标注为 Point 类型,但是,它的值却是 Point2D 的实例,并且没有类型错误。
3.因为 TS 是结构化类型系统,只检查 Point 和 Point2D 的结构是否相同(相同,都具有 x 和 y 两个属性,属性类型也相同)。
4.但是,如果在 Nominal Type System 中(比如,C#、Java 等),它们是不同的类,类型无法兼容。
除了 class 之外,TS 中的其他类型也存在相互兼容的情况,包括:1 接口兼容性 2 函数兼容性 等。
l 接口之间的兼容性,类似于 class。并且,class 和 interface 之间也可以兼容。 函数之间兼容性比较复杂,需要考虑:1 参数个数 2 参数类型 3 返回值类型。
参数个数,参数多的兼容参数少的(或者说,参数少的可以赋值给多的)。
type addOne =(x:number,y:number)=> void
type addTow =(x:number,y:number,z:number)=> void
let f1: addOne
let f2:addtTwo = f1
参数类型,相同位置的参数类型要相同(原始类型)或兼容(对象类型)。
type addOne =(x:number,y:number)=> string
type addTow =(x:number,y:number,z:number)=> string
let f1: addOne
let f2:addtTwo = f1
返回值类型,只关注返回值类型本身即可 如果返回值类型是原始类型,此时两个类型要相同,比如,左侧类型 F5 和 F6。 如果返回值类型是对象类型,此时成员多的可以赋值给成员少的,比如,右侧类型 F7 和 F8。
交叉类型
交叉类型(&):功能类似于接口继承(extends),用于组合多个类型为一个类型(常用于对象类型)。
type addOne =(x:number,y:number)
type addTow =(z:number)
let f1 = addOne & addTow
使用交叉类型后,新的类型 PersonDetail 就同时具备了 Person 和 Contact 的所有属性类型
type addTow =(x:number,y:number,z:number)
交叉类型(&)和接口继承(extends)的对比: 相同点:都可以实现对象类型的组合。
不同点:两种方式实现类型组合时,对于同名属性之间,处理类型冲突的方式不同。
interface addOne {fn: (x:number,y:number) =>string}
interface addTow extend addOne{fn: (x:string,y:number) =>string}
interface addOne {fn: (x:number,y:number) =>string}
interface addTow extend addOne{fn: (x:string,y:number) =>string}
type c = addOne & addTow
泛型 和 keyof
泛型是可以在保证类型安全前提下,让函数等与多种类型一起工作,从而实现复用,常用于:函数、接口、class 中
function addOne<T> (x:T):T =>return x
1.语法:在函数名称的后面添加 <>(尖括号),尖括号中添加类型变量,比如此处的 Type。
2.类型变量 Type,是一种特殊类型的变量,它处理类型而不是值。
3.该类型变量相当于一个类型容器,能够捕获用户提供的类型(具体是什么类型由用户调用该函数时指定)。
4.因为 Type 是类型,因此可以将其作为函数参数和返回值的类型,表示参数和返回值具有相同的类型。
5.类型变量 Type,可以是任意合法的变量名称。
简化
let add = addOne<number>(10)
泛型约束:默认情况下,泛型函数的类型变量 Type 可以代表多个类型,这导致无法访问任何属性。
比如,id('a') 调用函数时获取参数的长度
function addOne<T> (x:T):T =>{
console.log(x.length) //错误
return x
}
1 指定更加具体的类型 改正
function addOne<T> (x:T[]):T[]=>{
console.log(x.length)
return x
}
2 添加约束。 改正
interface Ilength {
length: number
}
function addOne<T extend Ilength> (x:T[]):T[]=>{
console.log(x.length)
return x
}
泛型的类型变量可以有多个,并且类型变量之间还可以约束
function addOne<T,y extend T> (x:T,y : y)=>{
console.log(x.length)
return x.y
}
泛型接口:接口也可以配合泛型来使用,以增加其灵活性,增强其复用性
interface Ilength <T> {
add :(value: T)=>T
}
泛型类:class 也可以配合泛型来使用。
比如,React 的 class 组件的基类 Component 就是泛型类,不同的组件有不同的 props 和 state
interface Istate { count: number}
interface Iprops{ maxvalue: number}
class InputCount extend React.Component<Istate,Iprops> {
state:Istate ={
count :1
}
render(){
return <div>{this.props.maxvalue}</div>
}
}
创建泛型类:
class InputCount<numType> {
defaultValue:numType,
add: (x:numType,y:numType) =>numType
}
const myNum = new InputCount<number>()
myNum.InputCount = 10