typeScript 深入了解
1.ts 静态类型
就是定义数据类型后,不可改变,还有深层级的理解,就是继承定义变量的属性及方法。
基础静态类型 冒号后跟数据类型 可以跟 number string null undefinde boolean void
const guan:{ name:string, age:number } = { name:'关关', age:19 } const guan2 :string [] = ['谢大脚','刘英'] // 定义数组类型,里面是字符串类型 class Preson{} const guan3 :Preson = new Preson() const guan4 :()=>string = ()=>{return '广告'}2.ts 类型注解和类型推断
类型注解
let count : number cont = 123 // 鼠标放上 会有提示 nmuber 类型类型注解
const one = 1 const two = 2 const three = one + two // 鼠标放上 自动推断出 three 是 number 类型
function getTotal(one,two) { return one + two } const total = getTotal(1,2) // 这时鼠标放到 total 上 显示 any 则推断不出来返回是什么类型 function getTotal(one:number,two:number) { return one + two } const total = getTotal(1,2) //这时鼠标放到 total 上 显示number可以判断出 对象中常量的类型
const guan5 = { name:'guanguan', age:18 } // 鼠标放到 Guana5 上会显示 name : string age:number3.初识 interface
因为 interface 这个概念在js中并没有,所以 interface 编译后并不会呈现到 js 中,只会进行静态的类型检查。
// 没用之前 const getFn = (name:string,age:number,bust:number)=>{ console.log('姓名:', name); } getFn('12',2,2) // 用interface interface Girl { name:string; age:number; bust:number } const girl = { name:'关关', age:12, bust:90 } const getFn = (girl:Girl)=>{ console.log('姓名:', girl.name); } getFn(girl)
会发现相同得传值地方很多,需要每次去写,不优雅,代码繁琐。你就会问和 类型别名 type ,其实是一样得就一点 不同,type 是直接可以赋值得,但是 interface 传递就必须是一个对象。
type Girl1 = string
想要传递更多参数,但是又不是必填字段,该怎么写?在后面添加一个问号interface Girl { name:string; age:number; bust:number; like?:string; } const girl = { name:'关关', age:12, bust:90, like:'帅哥' } const getFn = (girl:Girl)=>{ console.log('喜欢:',girl.like); } getFn(girl)
如果 like 后面没有跟 ?console.log(girl.like) 报错了。
这个时候你又应该问了,几个参数还可以写,要是很多参数怎么办,总不能一个一个写吧 ,哈哈。ts 也帮我们解决了,如下 [propname:string] 代表属性名是字符串类型,他得值是 any 任何类型。
interface Girl { name:string; age:number; bust:number; like?:string; [propname:string]:any } const girl = { name:'关关', age:12, bust:90, like:'帅哥', sex: '女', eat:'苹果' } const getFn = (girl:Girl)=>{ console.log('喜欢:',girl); } getFn(girl)给 Girl 添加一个说话得方法
interface Girl { name:string; age:number; bust:number; like?:string; [propname:string]:any; say():string } const girl = { name:'关关', age:12, bust:90, like:'帅哥', sex: '女', eat:'苹果', say:(()=>{return '123'}) } const getFn = (girl:Girl)=>{ console.log('喜欢:',girl.say()); } getFn(girl)extends与implements的不同
1.在类得声明中,通过关键字 extends 来创建一个类得子类。一个类通过 implements 声明自己使用一个或者多个接口。
2.extends 是继承某个类,继承之后可以使用父类得方法,也可以重写父类得方法。
interface Girl { name: string; age: number; bust: number; like?: string; [propname: string]: any; say(): string } interface Teacher extends Girl { teach(): string } class Preson implements Girl { name = '111' age = 12 bust = 90 say() { return '欢迎光临' } } const girl = { name: '关关', age: 12, bust: 90, like: '帅哥', sex: '女', eat: '苹果', say: (() => { return '123' }), teach: (() => { return 'jdijisodsids' }) } const getFn = (girl: Teacher) => { console.log('喜欢:', girl.teach()); } getFn(girl)4.类的使用
class Lady { content = 'hi 你好啊' sayHello() { return this.content } } class Gril extends Lady{ content = "不开心", sayHello() { return super.sayHello() + '111' // 使用父类中sayHello 方法 } } let LadyClass = new Gril() console.log(LadyClass.sayHello()); // 不开心 console.log(LadyClass.content); // 不开心5.类的访问
private 私有的 不能在外部及继承中使用,代码提示会报错,无法使用
protected 保护的 能在内部使用,不能在外部使用 但是在继承中是可以使用的
pulbic 公有的 在内部和外部都是可以调用的
类的内部和外部 {}外是外部 {}内是内部
class Person { public name: string | undefined; protected say(){ console.log(this.name + '你好啊'); return this.name + '你好啊' } } const person = new Person() person.name = 'jsGuan' person.say() console.log(person.say());name 如果不写就是默认为 public 所以在内部,外部是能访问的 person.name x现在把 say 方法写 protected 就会发现在外部是调用 say 方法是有访问不到的。
6.类的构造函数
class Person { public name : string | undefined constructor(name:string){ this.name = name } } const person = new Person('guanguan') console.log(person.name); // guanguan // 简便写法 class Person { constructor( public name:string){ } } // 继承 子类只有是构造函数 constructor 就必须调用super() 方法 class Person { constructor( public name:string){ } } class Son extends Person{ constructor(public age:number) { super('jingjing') } } const son = new Son(12) console.log(son.name); // jingjing console.log(son.age); //127.类的Getter setter static
class xiaoJieJie { constructor(private _age:number){ } get age () { return this._age } } const mom = new xiaoJieJie(18) console.log(mom.age);比如小姐姐类的年龄,不想让外界知道,所以 用 private 保护起来,通过 get 方式 renturn 出去。可以在 get 方法里面做一些操作封装一下等等。先执行 set 在执行 get
class xiaoJieJie { constructor(private _age:number){ } get age () { console.log(2); return this._age + 1 } set age (age:number) { console.log(1); this._age = age + 10 } } const mom = new xiaoJieJie(18) mom.age = 20 console.log(mom.age); // 31
补充一个 静态类的方法
不需要在实例化 一个对象 进行调用,直接用 class.方法属性
class Girl { static sayLove() { return 'I love you' } } console.log(Girl.sayLove());只读属性 readonly
class Person { public readonly _name :string constructor(name:string) { this._name = name } } const person = new Person('guanguan') person._name = 'jingjing' // 报错 因为 _name 属性是只读属性 console.log(person._name);
8.抽象类
概念:和父类很像都需要继承,抽象类一般都有一个抽象方法,继承抽象类的类,必须实现抽象方法才可以
关键字 abstract// 每一个类都需要一个技能 但是 每一个类里面 他们的技能是不同的 可以用抽象类 abstract class Girl { abstract skill():any // 没有大括号,因为每一个类的方法是不同的,所以不同写上 abstract say() :any } class waiter extends Girl { skill() { // 实际操作逻辑 console.log(1); } say() { console.log(2); } } class Baseteacher extends Girl { skill() { console.log(3); } say() { console.log(4); } }9.联合类型和类型保护(也叫类型守护)
只有参数有或者有2种以上这种方法就叫做联合类型
interface son { anjiao:boolean; say: ()=>{ la:string age:number } } interface teacher { anjiao:boolean; sayBey: ()=>{ la:string age:number } } function whatHow(animal:son | teacher) { }
animal.say() 发现会报错。因为你不知道这个 say() 方法是谁的,所以这个时候就会用到类型守护。
2.in 方式
3.typeof
4.instanceof
interface son { anjiao:boolean; } interface teacher { anjiao:boolean; sayBay: (()=>{}) } function whatHow(animal:son | teacher) { if (animal.anjiao) { (animal as son).anjiao console.log(animal.anjiao); } else { (animal as teacher).sayBay() console.log( (animal as teacher).sayBay()); // 'wowowo' } } const Girl = { anjiao:false, sayBay(){ return 'wowowo' } } whatHow(Girl)in 方式 ('skill' in type)
interface son { anjiao:boolean; skill :(()=>{}) } interface teacher { anjiao:boolean; sayBay: (()=>{}) } const Girl = { anjiao:false, sayBay(){ return 'wo shi saybay' } } function towho(type:son | teacher) { if ('skill' in type) { type.skill() console.log( type.skill()); } else { type.sayBay() console.log( type.sayBay()); // 'wo shi saybay' } } towho(Girl)
function add(frist: number | string, second: number | string) { if (typeof frist === "string" || typeof second === "string") { return `${frist}${second}` } return frist + second }10.tyepscript 命名空间 namespace
1.新建一个文件夹 放到 vscode 中 ,然后打开终端,允许 npm init -y 创建 package.json 文件。
2.生成文件后,我们直接在终端允许 tsc -init ,生成 tsconfig.json
3.新建 src 和 build 文件夹,在创建一个 index.html
4.在 src 目录下,新建 一个 page.ts 文件,开始要编写 ts 文件了。
5.在配置 tsconfig.json 文件,设置 outDir 和 rootDir, 也就是设置需要编译的文件目录,和编译好的文件目录。
6.然后编写 index.html,引入,当让我们现在还没有 page.js 文件
7.编写page.ts文件,加入一句输出console.log('你好 关关'),再在控制台输入tsc,就会生成page.js文件
8.再到浏览器中查看 index.html 文件,如果按F12可以看到你好 关关,说明我们的搭建正常了。
看到上面还是没有使用命名空间时,Top Contrnt Footer 都是全局变量,容易造成全局变量混乱,所以需要进行模块化的划分,这个时候就需要 进行命名空间,关键字时 namespace 写法在 page.ts 中注释那样进行编写。
这个语法,很类似编程中常说的模块化思想,比如webpack打包时,每个模块有自己的环境,不会污染其他模块,不会有全局变量产生。命名空间就跟这个很类似,注意这里是类似,而不是相同。
命名空间声明的关键词是namespace比如声明一个namespace Home,需要暴露出去的类,可以使用export关键词,这样只有暴漏出去的类是全局的,其他的不会再生成全局污染了
index.html script 修改
new Home.Page();深入了解 命名空间,接近实战,命名空间组件化