编译TS
安装tsc指令:npm install typescript -g
安装完成,查看版本号:tsc -v
在开发目录中,执行"tsc 文件名"指令,即可编译ts文件
监听并发布
1 通过tsc -init创建tsconfig,json配置文件
outDir定义js文件发布位置
2 执行tsc -w监听并发布文件
注:后面会使用工程化工具来自动化的编译ES6与TS(webpack)
数据类型
数据类型
在ts中所有的数据都要指明类型
在js中的数据类型,ts中都支持,并且还扩展了:any(任意类型)、void、never这些类型
类型猜测:
如果定义的数据没有指明类型,此时程序运行的时候根据赋值的数据进行类型猜测
但是,不要让ts去猜测类型:
1 程序执行的时候,会对数据进行猜测,会临时分配内存空间,造成消耗性能
2 类型猜测往往不是我们要的结果
类型推断:
当我们比程序更了解数据类型的时候,此时可以使用类型推断技术,让计算机按照某种类型去运行
语法:
第一种语法:<type>数据
第二种语法:数据 as 类型
类型推断并没有改变数据类型,不同于类型转换
类型声明语法
let 变量: 类型;
let 变量: 类型 = 值;
function fn(参数: 类型, 参数: 类型): 类型 {
...
}
自动类型判断
ts拥有自动的类型判断机制
当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
所以如果你的变量的声明和赋值是同时进行的,可以省略掉类型声明
类型断言
可以用来告诉解析器变量的实际类型
s = e as string;
s = <string>e;
上面两种方式等价
语法:
变量 as 类型
<类型>变量
类型
number 任意数字
string 任意字符串
boolean 布尔值true或false
字面量 限制变量的值就是该字面量的值
any 任意类型
unknown 类型安全的any
void 没有值(或undefined)
never 不能是任何值
object 任意的js对象
array 任意js数组
tuple 元组,TS新增类型,固定长度数组
enum 枚举,TS中新增类型
-
any
any表示任意的类型,一个变量设置类型为any后相当于对该变量关闭了TS的类型检测 使用TS时,不建议使用any类型 let d: any;
-
unknown
表示未知的类型 unknown实际上就是一个类型安全的any unknown类型的变量,不能直接赋值给其它的变量
-
void
void用来表示空,以函数为例,就表示没有返回值的函数 function fn(): void{ // return true // 不能写返回值,不然报错 可以写return空,或者Undefined,null,不报错 return return undefined return null }
-
never
never表示永远不会返回结果,连undefined都不返回 function fn(): never{ // 报错函数中断了,就永远不会返回结果 throw new Error('报错了') }
-
object
object表示一个js对象,不常用 let a: object; a = {}; a = function () {}; // {}用来指定对象中可以包含哪些属性,常用 // 语法:{ 属性名: 属性值, 属性名: 属性值 } let b: { name: string }; b = { name: 'hello' }; // 在属性名后面加上?,表示属性是可选的,可以写,可以不写 let b: { name: string, age?: number }; b = { name: 'hello', age: 18 }; b = { name: 'hello' }; // [propName: string]: any 表示任意类型的属性 let c: { name: string, [propName: string]: any }; // 表示对象中一定有name属性,其它的不确定 c = { name: 'xiaoming', age: 18, gender: '男' } // 设置函数结构的类型声明 // 语法:(形参: 类型, 形参: 类型 ...) => 返回值 let d: (a: number, b: number) => number;
-
array
数组的类型声明: 1 类型[] 2 Array<类型> // string[] 表示字符串数组 let e: string[]; e = ['a', 'b', 'c'] // number[] 表示数值数组 let f: number[]; // 表示数值数组 let g = Array<number>; g = [1, 2, 3]
-
tuple
元组就是固定长度的数组 语法: [类型, 类型, 类型] let h: [string, string]; // 表示元组有两个值,类型都是string h = ['hello', 'world'];
-
enum
枚举 enum Gender{ Male, Female } let i: { name: string, gender: Gender }; i = { name: 'xiaoming', gender: Gender.Male } console.log(i.gender === Gender.Male)
&表示同时
let j: { name: string } & { age: number }; // 必须包含name和age
j = { name: 'xiaoming', age: 18 }
类型的别名
可以简化类型的使用
type myType = 1 | 2 | 3 | 4 | 5;
let k: myType;
let l: myType;
let m: myType
数组
在ts中定义数组也要指定类型
语法:let arr:type[] = []
此时:
我们向数组中传递数据的时候,必须和初始化的时候,定义的数据类型是一致的
如果类型不确定,我们可以将type改变any
元组
定义元组的方式与定义数组很像,只不过在定义的时候,要指定类型以及指定个数
语法:let arr:[type1, type2] = [item1, item2];
此时:
1 传递数据的时候,必须和初始化的类型是一致的
2 传递数据的时候,必须和初始化的数据个数一致
3 在后面向元组中添加新成员的时候,必须在指定的类型范围之内
类型级联
如果定义的数据没有确定的类型,我们可以将数据的类型改为any
但是,any类型表示的数据范围太大了,为了缩小数据类型的范围,要使用类型级联技术
语法:type1|type2|type3
此时,定义的数据类型只能在该范围之内,a只能是number或者boolean
var a:number|boolean = 100;
枚举类型
枚举类型是介于对象和数组之间的数据类型
语法:enum 枚举类型 {}
特点:
即可以像数组那样,通过索引值获取属性名
又可以像对象那样,通过属性名称获取索引值
注意:
1 枚举类型数据的首字母要大写
2 每一个成员之间用逗号分隔
3 我们可以为某个成员改变索引值。此时,后面的成员索引值要递减,前面的不变
函数
在js中定义函数的方式有; 1 构造函数 2 函数定义式 3 函数表达式 4 箭头函数
只有函数定义式,不需要定义var或者是变量来接收
在ts中要为每一个函数指明类型
语法:function demo(arg:type, arg1?:type):type {}
传递参数:
1 传递的数据类型要一致
2 传递的数据个数要一致
函数注意事项:
1 函数中参数以及返回值要定义类型
2 如果参数可有可无,后面加上问号即可
函数的返回值通常有三类结果:
1 返回数据,此时函数的返回值类型就是数据类型
2 没有返回数据,函数的类型是void
3 如果函数中出现了错误,此时函数的类型是never
泛型
如果参数的类型是任意的,返回的结果也可以是任意的,此时我们可以将类型定义为any。
如果希望参数与返回值的类型是一致的,any类型就不适用,此时可以使用泛型
语法 function demo<T>(arg:T):T {}
这样的话,参数与返回值的类型就一致了,都是T变量表示的类型
使用函数的时候,有两种方式
第一种 demo<type>(数据)
第二种 demo(数据)
此时将猜测类型,常用
function fn<T>(a: T): T {
return a;
}
// 可以直接调用具有泛型的函数
fn(10); // 不指定泛型,TS可以自动对类型进行推断
fn<string>('hello') // 指定泛型
// 泛型可以同时指定多个
function fn2<T, K>(a: T, b: K): T {
console.log(b)
return a;
}
fn2<number, string>(123, 'hello')
// 类型接口
interface Inter{
length: number;
}
// T extends Inter表示泛型T必须是Inter实现类(子类)
function fn3<T extends Inter>(a: T): number{
return a.length;
}
fn3('123'); // 传入的参数必须符合Inter,即具有length属性,'123'是字符串,具有length属性
fn3(123); // 会报错。数字,没有length属性
fn3({ length: 10 }); // 可以,不报错
类
语法:class 类名{}
注:类名首字母要大写
构造函数:我们也是通过constructor定义构造函数
我们只能定义参数类型,不能定义返回值的类型。参数可有可无,后面添加?
属性:在ts中,我们要将属性在类体中声明类型
声明的时候可以赋值,但必须要设置类型
在构造函数中,也可以为声明的属性赋值。没有声明属性,在构造函数中,是不能使用
我们用构造函数的参数为属性赋值,实现数据由外部流入内部
属性必须在声明的时候赋值或者构造函数内部赋值
方法:定义方法的语法与ES6的语法是一样的。要声明参数以及返回值的类型
关键字:ts支持private, protected, public, static等关键字
但是private, protected, public在js中无法实现,或者实现成本很高,所以编译的时候,直接删除了,
static定义的静态属性可以实现。直接在数据前面加上static,就可以得到一个静态的属性了
ES6中,可以在类的外部,添加静态属性,但是在ts中,不能在外部添加属性,只能修改(在类中声明)
实例化:我们在实例化的时候,出现了变量,因此要定义变量的类型
变量的类型就是类。传递的参数要与构造函数一致
ts编译成rs3.1版本的语法,因此定义的类是一个闭包类
-
定义类
class 类名 { 属性名: 类型; constructor(参数: 类型) { this.属性名 = 参数 } 方法名() { ... } }
-
示例
class Person{ name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } // 如果方法前面加static,就是一个静态方法 sayHello() { console.log('hello') } // 静态属性,在属性前使用static关键字可以定义类属性(静态属性),只能通过类名来访问 static title: string = 'some' } // 访问静态属性 Person.title
抽象类
以abstract开头的类是抽象类 抽象类和其它类区别不大,只是不能用来创建对象 抽象类就是专门用来被继承的类
继承
TS中的继承:
语法:class 字类 extends 父类 {}
继承后,我们可以重写方法,此时优先使用我们重写的方法。
如果重写构造函数,
我们要使用super关键字实现构造函数继承
如果传递了参数,要与父类的参数一致(类型一致,个数一致)
属性要在super关键字之后赋值
ts中的继承是通过:寄生组合式的继承
模块
ts允许我们在文件内部定义模块
通过module关键字定义模块
在模块内部,通过export关键字暴露接口
模块的本质就是对数据添加了命名空间。所以使用数据的时候,要通过命名空间来访问
ts中的模块是通过闭包实现的
函数接口
接口:指的是一种数据结构,用interface关键字定义
语法 interface 接口名称{ 只定义结构,不要去实现 }
函数接口:
在函数表达式中,出现了变量,为了说明变量的结构,我们要定义接口
在函数中,函数的参数以及返回值属于结构,所以我们只需要定义这些数据的类型
interface 函数接口 {
(arg?:type):type
}
如果参数可有可无,要添加?
对象接口
在对象中,对象的属性以及方法的参数与返回值属于对象的结构
interface 对象接口 {
key?:type,
method(arg?:type):type
}
参数可有可无,后面添加问号
属性名称和方法可有可无,后面添加问号
类的接口
类接口与对象接口一样,也是定义类的结构:
在类中,类的属性以及方法的参数与返回值属于类的结构
interface 对象接口 {
key?:type,
method(arg?:type):type
}
注意:类实现接口用implements关键字
实例化类的时候,变量的类型
如果是类的类型,可以使用类中的所有属性方法
如果是接口类型,只能使用接口中声明的属性和方法
接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法
同时接口也可以当成类型声明去使用
interface myInterface{
name: string,
age: number
}
const obj: myInterface = {
name: 'xiaoming',
age: 18
}
接口可以在定义类的时候去限制类的结构
接口中的所有的属性都不能有实际的值
接口只定义对象结构,而不考虑实际值
interface myInter{
name: string,
sayHello(): void;
}
定义类时,可以使类去实现一个接口
实现接口就是使类满足接口的要求
class MyClass implements myInter{
name: string;
constructor(name: string) {
this.name = name
}
sayHello() {
console.log('hello')
}
}