typescript 安装
npm install -g typescript
检查是否安装 tsc -v
英文文档:https://www.typescriptlang.org/
中文(不长更新)www.tslang.cn
第一节:
新建01.ts 在里面写js语句
tsc 01.ts 生成js文件 //编译typescript
node 01.js 运行js文件
以上步骤复杂 每次更改要tsc生成
配置vscode ,自动编译成js文件 。在项目根目录生产tsconfig.json : tsc --init
vscode菜单上, 终端-运行-tsc监视 --当前项目 。
完成后自动生成和打包js文件
可以在tsconfig.json中配置生成的目录地址 例如:outDir:"./dist" 放在dist文件夹中自动生成
学习时不生产直接执行ts。 node 01.ts
懒人方式不想打命令时 :安装code runner 。 启用后 右键运行runner
会出现乱码,安装一个ts-node 。 npm i -g ts-node
第三节课:
let num :number =100; //强制设置number类型
如果有ts语法了 就必须用ts-node 01.ts 运行ts文件
不能强制转换类型,
数组内数据类型不同时 let arr:[number,string,boolean]
TS的特殊类型
1,any(任意值) 2、null(不存在的对象) 3、undefined(声明但未初始化赋值)
4、void(空值,无返回,不允许返回)
第四节:枚举类型(包裹相关的声明变量的一种方式。优势明显,代码优雅,提高了可读性)
enum weeks{
one,two,tree,four
}
console.log(weeks['four']);或weeks.four
枚举类型可以强制更改里面的类型,但是后面也必须更改
weeks[0] 可以得到键名。
const 可以变成常数枚举。
const enum Info{ name = 'mr.lee' ,age=20}
第五节: 联合类型和字面量
创建一个字面量类型 let myName : 'Mr.pan' = 'Mr.pan' 赋值和类型要一样, 例如性别只能是男或女
let gender : '男' | '女' //这里是类型
gender = '男' //这里是值
2. 联合类型 :使用| 表示多种类型的声明
let numPrStr : number | string
numOrStr = 100 或 numOrStr = 'tomg' 都不会报错
方法中: function info(other:number|string){ } //输出数字和字符串都可以
第六节:类型推断和断言
1. 什么是类型推断:如果不使用注解对变量进行类型定义,ts将自行对变量类型进行判断 。初始值是什么类型就固定成什么类型。
如果初始没有赋值 ,那么这个变量是any(任意类型)。输出最后赋值的值 。其他赋值不会报错
如果是方法 ,例如 function info(num1,num2) {} //有报错,在tsconfig.json 文件中第28行 "strict:false",改成非严格模式。
正常来讲必须严格模式。 可以给参数家类型 info(num1:number,num2:string){}
2. 类型断言,在联合类型传参的时候,我们需要根据判断类型做响应的处理。
访问联合类型时,会检查所有类型都是否具备这个属性。如果 function info(info:number|string){ if(info.length) }
这里的info.length会报错,因为number没有长度属性。 此时;需要做类型的断言操作
断言类型有两种:
第一种 .<类型> 值; //后续另一种类型也有这种符号,易混淆
第二种 .值as类型; //推荐这种 ,jsx只支持这种
function info(info:number|string){ if((info as string).length){ return (info as string).length } else{ return info.toString().length}} //先强行推断为字符串 .否则是数值就toString强行转换为字符出串。
第七节:类的使用
主要概念为:面向对象的思维、类、三大特性(封装,继承,多态)等知识点、
//创建类
class Person{
name:string
age:number
constructor(name:string,age:number){
this.name = name
this.age =age
}
run():string{
return this.name+'的年龄是:'+this.age
}
}
let p = new Person('Mrs.pan',30);
console.log(p.run())
第八节:类的继承
子类继承父类拥有父类的属性和方法,也可以再创建自己独有的特性;
ts支持多重继承,不支持多继承(一个子类继承多个父类)
//人类
class Person1{
name:string
age:number
constructor(name:string,age:number){
this.name = name
this.age =age
}
run():string{
return this.name+'的年龄是:'+this.age
}
}
//子类 ,男的
class Man extends Person1{}
let m = new Man('男的',40);
console.log(m.run());
//子类,女的
class Woman extends Person1{
//独有成员
food:string='晚餐'
//独有方法
eat():string{
return this.name +'吃'+this.food
}
}
let w =new Woman('女士',44)
console.log(w.run())
console.log(w.eat());
//孙子类(多重继承) ,奶奶
class OldWoman extends Woman{}
let o = new OldWoman('老奶奶',80);
console.log(o.eat())
第九节:类方法的重写
类方法分为构造方法和普通方法。实现重写机制; 继承的子类互不干涉
//人类男
class Person2{
name:string
age:number
constructor(name:string,age:number){
this.name = name
this.age =age
}
run():string{
return this.name+'的年龄是:'+this.age
}
}
//子类 ,男的
class Man2 extends Person2{
heigt:string
//构造函数重写
constructor(name:string,age:number,heigt){
//super关键字调用父类的构造方法
super(name,age)
this.heigt = heigt
}
//普通方法重新
run():string{
//普通方法采用super.方法调用
return super.run()+',身高是'+this.heigt
}
}
let m2 = new Man2('男的',40,1.90);
console.log(m2.run());
//子类,女的
class Woman2 extends Person2{}
let w2 =new Woman2('女士',44)
console.log(w2.run());
输出:
男的的年龄是:40,身高是1.9
女士的年龄是:44
第十节:类方法的重载
1.类方法的重载,即:方法相同但传参数不同从而执行不同的一种操作:
2.例如构造方法里,只能传一个参数,也可能只传递两个参数来实现不同效果;(参数相同但可选)
3.普通方法重载类似
//闭包解决重名
(function(){
class Person{
name:string
age:number |undefined
constructor(name:string,age?:number){
this.name = name
this.age =age
}
//?:是可选参数,参数会变成两个类型**和undefined
run(flag?:boolean):string{
if(flag ===false){
return '无法显示'
}
if(this.age===undefined){
return this.name+'的年龄保密'
}
return this.name+'的年龄是:'+this.age
}
}
let p1 = new Person('男的',40)
console.log(p1.run(false));
let p2 =new Person('女的')
console.log(p2.run());
})()
输出:
无法显示
女的的年龄保密
第11节课:类成员的修饰符
1.不加修饰符情况下,成员字段和方法默认公共public完全可见的状态。
2.如果设置不同的可见性,一共三种方案:
(1) .public :默认设置,公有可见性;
(2) .protected :受保护的,自身和子类可访问;
(3) .private :私有的,只能自身访问;
3. 方法和构造方法也可以设置修饰符。
构造方法前加了protected 父类就不能实例化了 ,只有子类能够实例化。 如果没有子类,受保护和私有修饰符都可以
第12节课:类成员的存取器
1.成员字段访问
成员字段我们进行了封装保护,那么除了实例化的方案外,还怎么对外暴漏接口?
可以通过:setXXX()和getXXX()约定俗称的方法来实现对成员字段的取值赋值。
2.成员字段存取器
成员字段有专门的setter和getter方法来处理私有成员字段的取值赋值
class Person{
// protected _name:string
// protected _age:number
// constructor(_name:string,_age:number){
// this._name = _name
// this._age =_age
// }
//声明和构造简写方案,语法糖
constructor(private _name:string,private _age:number){
this._name =_name
this._age =_age
}
//setter
set name(name:string){
this._name =name
}
//getter
get name(){
return this._name;
}
run():string{
return this._name+'的年龄是:'+this._age
}
}
let p = new Person('Mrs.v',30);
console.log(p.run());
p.name="Mr.lin"
console.log(p.run());
console.log(p.name);
第13节 :静态成员和方法
1. static 关键字用于声明静态成员和方法,这是一种不需要实例化的调用方式;
2. 一般用于各种工具类,方便直接调用使用,较为方便;
3.设置静态不能修改只读加readonly
class Person{
name:string
age:number
//设置静态并且只读不能修改 static readonly
static readonly p:number =3.1415926
constructor(name:string,age:number){
this.name = name
this.age =age
}
static getPi(){
return '圆周率'+Person.p
}
//?:是可选参数,参数会变成两个类型**和undefined
run():string{
return this.name+'的年龄是:'+this.age
}
}
console.log(Person.getPi())
第14节:抽象类大的使用
1.抽象类可以用于顶层制定和设计标准,让子类继承时去实现具体细节;
2.抽象类设计相关成员和方法,不用于具体使用,所以无法实例化;抽象类的关键字 abstract
3.抽象类定义了规范
//抽象类
abstract class Person {
constructor(protected name:string,protected age:number) {}
//需要被子类实现的方法
abstract run():string
}
class Man extends Person{
constructor(name:string,age:number){
super(name,age);
}
run():string{
return this.name+'的真实年龄'+this.age
}
}
let m = new Man('Mrs.pan',30);
console.log(m.run());
第15节: 接口的访问
1.接口类类似于抽象类,只不过它更彻底,只提供标准却完全不实现细节;
2.具体表现在成员字段不可以赋值初始化,方法不可以实现。
不需要修饰符,都是public的
接口的实现:
//接口
interface Person{
name?:string
age?:any
run():string
}
interface Abc extends Person {
def():string
}
//子类实现Person接口
class Man implements Abc{
name:string ='mo'
age:number =90
run(){
return this.name+'的年龄是:'+this.age
}
def(){
return 'string'
}
}
let p = new Man();
console.log(p.run());
输出:mo的年龄是:90
3.接口的成员和方法必须由子类实现,也可以设置为可选方案让子类自由实现 属性: name?:string 方法:run?():string
PS:这样实现的子类就不必强制去初始化或实现接口中的成员和方法了;
PS:继承只能继承一个父类,是接口实现支持实现多个接口;
PS:并且,接口还可以继承另一个接口,从而进行合并;
第16节:对象的接口类型
//接口类型
interface Person{
name:string
age:number
gander?:'男'|'女'|'未知'
run():string
}
//对象字面量
let man : Person ={
name:'Mr.chen',
age:30,
gander:'男',
run(){
return this.name+'的年龄是:'+this.age+'岁'+ this.gander
}
}
console.log(man.run())
//接口的字段也可以设置任意属性,具体如下:
interface Person{
[arrtName:string]:any
}
//自定义任意类型
[attrName:string]:any
PS:此时,对应的对象可以自由添加各种属性和类型;
PS:左边的string表示属性key的类型,只支持string和number;
PS:右边的any表示值value的类型,和普通类型限制一样;
第17节:泛型的变量
一.泛型变量
1.js和ES6没有泛型的概念,并且如果也没接触过包含后端的泛型。
2.那么理解泛型会比较困难,所以,这里花几节课把最简单那的了解下即可
在类型不明确的时候,我们可以使用泛型来解决这个问题,提高了灵活性
泛型最核心大的部分就是下面例子中的<T>,T就是泛型变量,将类型赋给它;
function info<T>(msg:T):T{
return msg }
输出时1.可以自动推断 info(100) ; 返回100
如果要强制是string类型: info<string>('hello'); 返回string类型的hello
总结:泛型可以在调用的时候指定类型。 T是泛型变量 ,使用泛型代替any
第18节课: 泛型的数组
//普通数组
let arr :number[]=[1,3,4]
//不确定数组 T[]
//泛型数组
let arr1:Array<number>=[3,6,7]
//不确定数组 Array[T]
// function setArr(value:any):Array<any>{
// return [value]
// }
// console.log(setArr('z'));
// function setArr<T>(value:T):Array<T>{
// let result :T[] = [value,value]
// console.log(result.length);
// return result
// }
// //调用时类型规定是number类型
// console.log(setArr<number>(9));
//多个泛型灵活搭配
function man<T,P>(name:T,age:P):[T,P]{
return [name,age]
}
console.log(man<string,number>('Mr.pan',100))
第19节:泛型类型和接口
1.前面我们通过泛型变量的形式来存储调用方的类型从而进行检查;
2.而泛型也可以作为类型的方式存在,理解这点,先来接下函数的声明方式;
第20节:泛型类和约束
1.泛型也会有无法检查通过所有类型都具有同一个属性的问题,比如.length
2.使用泛型约束,继承接口
(function(){
//泛型约束
interface Ilength{
length:number
}
function info<T extends Ilength>(msg:T):T{
console.log(msg.length)
return msg
}
console.log(info<string>('Mr.pan'))
})()
第21节:模块化
1.模块化可以用来复用和组织我们的diamagnetic,避免代码重名。也方便分离
2.模块化也就是export(导出)和important(引入),es6讲解过,这里不再赘述;
3.那么,我们使用模块来分离我们的接口和类,然后通过模块调用;
exprot导出 , import 导入
IPerson.ts
//接口类,限制成员字段和方法
export interface IPerson{
name:string
run():void
}
Person.ts
import { IPerson } from "./Iperson"
//实现接口类
export class Person implements IPerson{
name:string = ''
constructor(name:string){
this.name =name
}
run(){
console.log(this.name +'运行了..')
}
}
21.ts
import{Person} from './modules/Person'
let p =new Person('Mrs.Lan')
p.run();