1、面向对象增强:TS是对面向对象思想进行了增强,使前端变成了强语言类型
(强语言类型:不会因赋值而改变数据类型,只能通过强制转换)
2、它有更多的规则和类型限制:代码具有更高的预测性、可控性,易于维护和调试;对模块、命名空间和面向对象 的支持,更容易组织代码开发大型复杂程序。
3、它是一个超集:它是以JavaScript为基础构建的语言,是一个编译到纯 JS 的有类型定义的 JS 超集,遵循当前以及未来的 ECMAScript规范。不仅能兼容现有的 JS 代码,它也拥有兼容未来版本的。
1.新建ts 文件index.ts.
2.ts 语法在浏览器是无法运行得,所以需要编译成js 语法,使用如下命令 tsc index.ts (缺点:每次更新,都需要重新编译)
3.初始化文件夹和自动监测,执行如下命令:
tsc --init
4.自动监测同步 JS 文件,执行如下命令:
tsc -w
5.所有的 TS 文件必须通过下列方式编译成 JS 文件后,才能必须页面执行
使用终端指令手动编译 tsc index.ts 使用终端指令自动编译 tsc --init 生成对应得 tsconfig.json文件 tsc -w 监测将ts文件编译成js文件。
语法:
let 变量:类型
let 变量:类型(number,boolean...)= 值(false/2/'sdf'...);
function fn(参数:类型,参数:类型):类型{
。。。。。。
}
let u:undefined =undefined;
let n:null = null;
//多个类型
let a:number|string|undefined = 100
//表示c的对象中必须有name属性,其他为可选项
let c:{name:string,[propName:string]:any}
any和unknown类型的区别
any表示的是任意类型,一个变量设置类型为any后相当于对该变量关闭了ts的类型检测,不建议使用,声明变量时如果不指定类型,则ts解析器会自动判断变量的类型为any(隐式的any),他可以赋值给任何变量
unknown在赋值给任意确定类型的变量时会报错 ,unknown实际上就是一个安全类型的any
类型断言:(在将unknown类型赋值时,报错的解决办法)
有些情况下,变量的类型对于我们来说是很明确,但是TS编译器却并不清楚,此时,可以通过类型断言来告诉编译器变量的类型,断言有两种形式:
语法:变量 as 类型 / 变量
//第一种
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
//第二种
let someValue: unknown = "this is a string";
let strLength: number = (someValue).length;
它是对 JavaScript 标准数据类型的补充,声明一组带名字的常量,当一个变量有多个取值的可能时,就可以定义为枚举型
语法: enum xxx{ 枚举名称 }
1、枚举类型
1.数字型枚举
当定义的枚举型成员是数字时,那么,该枚举就是数字型枚举,成员的数字既可以是指定的数字值,也可以是索引号,默认值从 0 开始,依次类推
enum direction {
up = 10,
dowm = 88,
left = 10,
right = 99
}
2.字符型枚举
在定义的枚举类型中,每个成员都是字符型字面量,它无法进行累加也不能初始化索引号,仅是给每个成员取了一个可读的名字, 反向映射。
enum direction {
up = 'up',
dowm = 'down',
left = 'left',
right = 'right'
}
3.异构型枚举
当一个定义好的枚举成员中,由数字和字符型联合构成,这种类型称之为异构型,即不同的类型构建在一起的枚举,(此类型很少使用)
enum status1{
success="ok",
code=500
}
4.常量型枚举
它是在普通枚举的基础上,使用 const 修饰符来定义,一旦定义成常量型的枚举,它的成员值只能使用常量,并删掉整个枚举定义内容
let d = 199
const enum direction{
up=10,
dowm,
left=10,
right = d 报错
}
2、反向映射
枚举类型中,通过成员名,可以很方便地访问到成员值,同时,通过成员值,也可以返回成员名称,这种方式称之为反向映射
enum direction {
up = 'up1',
dowm = 'down1',
left = 'left1',
right = 'right1'
}
direction['dowm'] = 'down1' 反过来 direction['down1'] = 'down'
3、枚举合并
多个枚举类型可以分开定义,并不会冲突,分开后,在编译时会自动合并,不影响成员中值的访问,具体代码如下:
enum direction {
up = 10,
dowm = 88,
left = 10,
right = 99
}
enum direction {
forward = 1000,
backward = 2000
}
console.log(direction) 合并到一块了
可选参数和默认参数和剩余参数:可选参数? 可以不用传,注意:如果还有其他参数,可选参数不能作为第一个参数
可选参数在参数后+?
function add(x:number,y?:number):number{
console.log(y)
return y?x+y:x
}
默认参数就是给参数赋值默认值
function fn1(name:string,sex:string ='男',age?:number):string{
return `${name}---${age}---${sex}`
}
剩余参数
...arr
function fn2(name:string="老杨",age?:number,...arr:any[]):string{
console.log(name,age,arr)
return ``
}
fn2(undefined,32,'男','北京','已婚')
接口的语法:使用 interface 关键字,后面添加接口的名称,并使用大括号描述接口中各结构属性的类型,完成定义后,可以像普通的类型一样使用它
接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法。接口主要负责定义一个类的结构,接口可以去限制一个对象的接口,对象只有包含接口中定义的所有属性和方法时才能匹配接口。同时,可以让一个类去实现接口,实现接口时类中要保护接口中的所有属性。
interface Person{
name:string,
age:number,
}
let p:Person = {
name:"沈腾",
age:40
}
1、接口属性
接口属性有 普通属性, 可选属性(?),只读属性(readonly)
普通属性:就是正常的属性
可选属性: 在使用该接口时,可选属性可传可不传。
只读属性:只读属性使用后,不能再次修改。
interface Person{
name?:string,
readonly age:number,
}
let p:Person = {
name:"沈腾", 可选属性 可传可不传
age:40 只读属性不能修改
}
2、接口定义函数
fn 表示一种函数数据类型
interface fn{
(m:string):void
}
let f1:fn = function(m:string){
console.log(m)
}
f1('xxxx')
接口中使用函数
如果在接口中有函数,可以在接口中直接定义
interface Men{
name?:string,
readonly age:number,
say:(m:string,n:number)=>string 第一种写法
say(m:string,n:number):string 第二种写法
}
也可以使用接口定义,再引入到接口中,这两种方式都可以实现
interface Say{
(m:string,n:number):string
}
interface Men{
name?:string,
readonly age:number,
say:Say
}
let bichen:Men = {
name:"xxx",
age:30,
say:function(m:string,n:number):string{
return `${this.name}----${m}`
}
}
3、可索引接口
定义:主要是来用定义数组或对象数据类型的。
1. 定义一个数组数据类型
interface arr{
[name:number]:any
}
let arr1:arr=['刘','关','张',100,{}];
2. 定义一个对象数据类型
interface obj{
[name:string]:any
}
let obj1:obj={
"sex":"男",
age:20
}
使用案例:
interface child{
name:string,
age:number,
say:()=>string,
like:obj
}
let liuyan:child={
name:"刘衍",
age:20,
say:():string=>{
return ``
},
like:{
"movie":"电影",
"play":"lol"
}
}
console.log(liuyan)
4、接口的继承
一个接口除被作为类型使用外,还可以被其他的接口继承,继承一个为单继承,二个以上为多接口继承,代码如下:
定义 women接口
interface women{
name:string,
age:number,
cook:(m:string)=>string
}
定义 father接口
interface father{
work:()=>string
}
定义 son接口继承women,father接口
interface son extends women,father{
play:string,
study:()=>string
}
let zhanhzhenda:son={
name:"张郑达",
age:20,
cook:(m:string):string=>{
return `我喜欢做${m}`
},
play:"lol",
study:():string=>{
return`我要毕业上班`
},
work:():string=>{
return `我要敲代码`
}
}
在es5中使用函数创建类
function Girl(name,age){
this.name = name
this.age = age
this.say=function(){
}
}
let fanbingbing = new Girl('范冰冰',40)
let liuyifei = new Girl('刘亦菲',32)
console.log(fanbingbing)
console.log(liuyifei)
在es6中使用class 创建类
注意:类的构造函数:constructor(){} ,一般在实例化类的时候,传参需要用constructor 构造函数接收参数的情形。所以这种情况下,才需要在类里写构造函数。否则不写。
指在构造(实例化)一个类时,执行的函数,故称为构造函数,它也是一个普通的函数,也能定义形参,在构造时传递实参, 该构造函数在实例化类的时候执行。如下:即在 new C('张三')的执行。
class Girl{
name:string;
age:number;
say():string{
return `大家好,我是${this.name}`
}
constructor(m:string,n:number){ 构造函数
this.name = m
this.age = n
}
}
let guanzhilin = new Girl('关之琳',40)
1、类的继承
// 定义 Girl类
class Girl{
name:string;
age:number;
say():string{
return `大家好,我是${this.name}`
}
constructor(m:string,n:number){ 构造函数
this.name = m
this.age = n
}
}
// 定义学生类 继承 Girl类
class Student extends Girl{
grade:string;
study():string{
return `我要学习web 前端`
}
say():string{
return `子类中方法,我是${this.name}`
}
constructor(m:string,n:number,g:string){
super(m,n)
this.grade = g
}
}
2、类的修饰符
class Person{
public name: string; // 写或什么都不写都是public
public age: number;
constructor(name: string, age: number){
this.name = name; // 可以在类中修改
this.age = age;
}
sayHello(){
console.log(`大家好,我是${this.name}`);
}
}
class Employee extends Person{
constructor(name: string, age: number){
super(name, age);
this.name = name; //子类中可以修改
}
}
const p = new Person('孙悟空', 18);
p.name = '猪八戒';// 可以通过对象修改
class Person{
protected name: string;
protected age: number;
constructor(name: string, age: number){
this.name = name; // 可以修改
this.age = age;
}
sayHello(){
console.log(`大家好,我是${this.name}`);
}
}
class Employee extends Person{
constructor(name: string, age: number){
super(name, age);
this.name = name; //子类中可以修改
}
}
const p = new Person('孙悟空', 18);
p.name = '猪八戒';// 不能修改
class Person{
private name: string;
private age: number;
constructor(name: string, age: number){
this.name = name; // 可以修改
this.age = age;
}
sayHello(){
console.log(`大家好,我是${this.name}`);
}
}
class Employee extends Person{
constructor(name: string, age: number){
super(name, age);
this.name = name; //子类中不能修改
}
}
const p = new Person('孙悟空', 18);
p.name = '猪八戒';// 不能修改
属性存取器
class Person{
private _name: string;
constructor(name: string){
this._name = name;
}
get name(){
return this._name;
}
set name(name: string){
this._name = name;
}
}
const p1 = new Person('孙悟空');
console.log(p1.name); // 通过getter读取name属性
p1.name = '猪八戒'; // 通过setter修改name属性
3、静态属性
存在于类本身上面而不是类的实例上,即无须实例化就可以访问的属性,称之为静态属性,使用static开头
1、先看es5中类的静态属性表示如下:
2、es6中类的静态属性
class Boy {
static name1: string = '周杰伦';
age: number;
static say(): void {
console.log(this.name1)
}
constructor(age: number) {
this.age = age
}
}
let jielun = new Boy(45)
// jielun.say()
console.log(Boy.say())
4、类类型接口
定义一个接口,声明一个类去实现(implements)接口,注意不是继承 如下:
interface Person {
name: string,
age: number,
say: (m: string) => void
}
// 使用类实现这个接口
class Man implements Person {
name: string;
age: number;
say(m: string): void {
console.log(this.name)
};
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
let wangyucao = new Man('小明', 10);
5、抽象类
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口, 抽象类可以包含成员的实现细节。 abstract关键字是用于定义抽象类和在抽象类 内部定义抽象方法。
抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。 然而,抽象方法必须包含 abstract关键字。
// 1. 特点 抽象类不能实例化
// 2. 抽象方法 不能写具体实现,必须在子类中写具体实现
abstract class Animal {
name: string;
age: number;
constructor(m: string, n: number) {
this.name = m
this.age = n
}
abstract run(): string
}
class Cat extends Animal {
constructor(m: string, n: number) {
super(m, n)
}
run(): string {
return `${this.name}在跑步`
}
}
let huahua = new Cat('花花', 5)
console.log(huahua)
定义:先定义一个变量代表传入的类型,再使用该变量,因此,它是一种特殊的变量,只代表传入的数据类型,不是一个固定的值,而是传什么是什么,而这种类型变量称之为泛型
// 普通函数1
const fn = (x:number)=>{
console.log(x)
}
// 普通函数2
const fn2 = (x:string)=>{
console.log(x)
}
// 普通函数调用
fn(1)
fn2('123')
//使用泛型定义简化上述方式
function fn(x: T): T {
return x
}
1、泛型在接口中的使用
interface fn1 {
(m: T): T
}
let f2: fn1 = function (m: any): any {
return ``
}
2、泛型在类中的使用
class obj1{
arr: T[] = [];
push(m: T) {
this.arr.push(m)
}
}
let obj = new obj1()
obj.push('及时雨宋江')
obj.push('黑旋风李逵')
obj.push('智多星吴用')
obj.push('豹子头林冲')
obj.push(100)
obj.push(true)
3、泛型约束
type a = string | number | boolean // 泛型加约束条件
class obj1{
arr: T[] = [];
push(m: T) {
this.arr.push(m)
}
}
let obj = new obj1()
obj.push('及时雨宋江')
obj.push('黑旋风李逵')
obj.push('智多星吴用')
obj.push('豹子头林冲')
obj.push(100)
obj.push(true)
4、泛型数组2种方
interface Array{
[name:number]:T
}
let arr3: Array