TypeScript基础知识梳理

核心提示TypeScript基础知识梳理 之前一直打算看看ts,但一直沉迷摸 无法自拔,公司目前项目中也没有ts项目。今年手上正好有两个小程序项目,于是打算用ts写一下,感受一下ts的“魅力”。顺便整理了一下学习笔记,希望能帮到有需要的人。同时也用

Typescript基础知识梳理

之前一直打算看看ts,但一直沉迷摸 无法自拔,公司目前项目中也没有ts项目。今年手上正好有两个小程序项目,于是打算用ts写一下,感受一下ts的“魅力”。

顺便整理了一下学习笔记,希望能帮到有需要的人。

同时也用XMind做了知识图谱,有需要源文件的可以留言。最后!记得点赞+关注支持一下。感谢支持 。

安装与编译安装npm install -g typescript //mac下安装前面需要加sudo编译
  • 可以执行下面命令进行编译,会在当前目录下产生一个test.js文件
tsc test.ts
  • 这样可能还是比较麻烦,我们可以借助插件方便我们提高效率:
npm install -g ts-node
  • 安装完后只需执行ts-node test.ts就可以在控制台查看输出结果。

原始数据类型
  • js中数据类型分两种,原始数据类型和对象类型,原始类型包括:布尔值、数字、字符串、null、undefined以及Symbol。
布尔值
  • 在Typescript中,使用boolean定义布尔值类型
let isStatus:boolean=true;数字
  • 使用number定义数值类型
let isNumber:number=1;//16进制let isNumber16:number:=0b1010;字符串
  • 使用string定义字符串类型:
let isString:string='hello word';let year:number=2020;let add:string=`${isString},${year}!`;空值
  • Javascript 没有空值(Void)的概念,在Typescript中,可以用void表示没有任何返回值的函数.
function alertName:void{ alert}
  • 声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null。
let unusable: void = undefined;Null 和 Undefined
  • 在Typescript中可以使用nullundefined来定义这两个原始数据类型
let u:undefined=undefined;let n:null=null;
  • 与 void 的区别是,undefined 和 null 是所有类型的子类型。

    也就是说undefined类型的变量,可以赋值给number类型的变量,而void类型的变量不能赋值给number类型的变量:

let num:number=undefined;//不会报错let u:undefined;let num: number = u;//也不会报错let u:void;let num:number=u;// Type 'void' is not assignable to type 'number'.任意值
  • 任意值(Any)用来表示允许赋值为任意类型。
什么是任意值类型
  • 如果是一个普通类型,在赋值过程中改变类型是不被允许的:
let renyiString:string='string';renyiString=8;//Type 'number' is not assignable to type 'string'.
  • 但如果类型是Any,类型,则允许被赋值为任意类型:
let renyiString:any='string';renyiString=8;
  • 在任意值上访问任何属性都是允许的:
let anyThis:any='hello';console.logconsole.log
  • 也允许调用任何方法:
let anyThing: any = 'Tom';anyThing.setName;anyThing.setName.sayHello;anyThing.myName.setFirstName;
  • 可以认为,声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。

未声明类型的变量
  • 变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型:
let something;something = 'seven';something = 7;something.setName;
  • 等于
let something: any;something = 'seven';something = 7;something.setName;数组的类型基础表示
  • 「类型 + 方括号」表示法
let numbers:number[]=[1,2,3,4,5]
  • 此时不允许出现其他类型,而且如果使用数组中push等方法,添加元素也得符合相应类型。

数组泛型
  • 我们也可以使用数组泛型(Array Generic) Array 来表示数组
let fibonacci:Array=[1,2,3,4,]
  • 如果数组中又有number类型又有string类型,则可以用符号来区别定义:
let arr:[]=['tom',1];数组中对象类型的定义
  • 项目中经常遇到数组中有对象的存在,对于这种就比较麻烦了,比如:
let arr:{name:string,age:number}[]=[{name:'tom',age:18}]
  • 这样就比较麻烦了,我们可以使用ts中的类型别名来解决这个问题:
type PeopleType={name:String,age:Number};let arr:PeopleType[]=[ {name:'bob',age:19}]
  • 也可以用类型定义也可以解决:
class PeopleType{ name:string; age:number}let arr:PeopleType[]=[ {name:'bob',age:19}]元组的使用和类型约束
  • 在数组中如果里面又有stringnumber,可以使用来进行定义,但一定程度上并不严格。比如改成下面这种格式:
let arr:[]=[111,'222',111];
  • ts并没有报错,如果想要严格限制,则可以这样进行约束:
let arr:[number,string,number]=[111,'222',111];Interface接口
  • 比如我们要做一个筛选,吧不符合条件的过滤出去,我们可能会这样写:
const types==>{age>=20 && height>=180 && console.log;age<=20 && height <180 &&console.log};types //符合条件
  • 但如果又修改了一些需求,可能还会去大量变更代码,在开发中,代码能复用肯定是最好的,所以可以把一些重复的代码抽离出来:
interface People{ name:string; age:number; height:number;}const types==>{ people.age>=20 && people.height>=180 && console.log; people.age<=20 && people.height <180 &&console.log};const choose==>{ console.log}const people={ name:'tom', age:18, height:178}types;choose;接口与类型别名的区别
  • 看起来两者没有什么区别,但有个小细节:类型别名可以直接给类型,接口必须代表对象
type People=string;interface People{ name:string; age:number; height:number;}
  • 如果传入的参数中有不确定项,我们可以使用 : 来进行处理:
interface People{ name:string; age:number; height:number; say :string};const types==>{ people.age>=20 && people.height>=180 && console.log; people.age<=20 && people.height <180 &&console.log};const people={ name:'tom', age:18, height:178}const people2={ name:'tom', age:18, height:178, say:'hello'}types;types;
  • 这时候又有新需求了,如何在后面加入任意多的字段?这时候我们就可以这么写:
interface People{ name:string; age:number; height:number; say :string; [propname:string]:any;}const types==>{ people.age>=20 && people.height>=180 && console.log; people.age<=20 && people.height <180 &&console.log};const people={ name:'tom', age:18, height:178, say:'hello', add:'new add', addNumber:123}types;接口里的方法
  • 接口不仅仅可以存属性,也可以存方法:
interface People{ name:string; age:number; height:number; goto:string;}const types==>{ people.age>=20 && people.height>=180 && console.log; people.age<=20 && people.height <180 &&console.log};const people={ name:'tom', age:18, height:178, goto{ return 'hello' }}types接口和类的约束
  • 在ES6中是有类的概念,类可以和接口相结合:
interface People{ name:string; age:number; height:number; goto:string;}const types==>{ people.age>=20 && people.height>=180 && console.log; people.age<=20 && people.height <180 &&console.log};const people={ name:'tom', age:18, height:178, say:'hello', add:'new add', addNumber:123, goto{ return 'hello' }};class newPeople implements People{ name='bob'; age=19; height:190; say:'hello'; add:'new add2'; addNumber:123; goto{ return 'hi' }};let a=new newPeople;console.log)types接口的继承
  • 接口与接口也是可以继承的:
interface People{ name:string; age:number; height:number; say :string; [propname:string]:any; goto:string;}const types==>{ people.age>=20 && people.height>=180 && console.log; people.age<=20 && people.height <180 &&console.log};const people={ name:'tom', age:18, height:178, say:'hello', add:'new add', addNumber:123, goto{ return 'hello' }, back{ console.log }}interface newPeople extends People{ back:void}types类的基本使用
  • 首先,我们先创建一个类:
class Test{ name='say' say{ return this.name }};
  • 这就是平时所写的类,在ts中的继承和ES6的继承是一样的,关键字也是extends,比如我们这里新建个类,继承Text;
class Test{ name='say' say{ return this.name }};class NewTest extends Test{ back{ return 'hello' }}const tom=new NewTest;console.log);console.log);super关键字的使用
  • 如果想在say方法中后面加点东西,可以这么操作:
class Test{ name='say' say{ return this.name }};class NewTest extends Test{ back{ return 'hello' } say{ return super.say+'----hello' }}const tom=new NewTest;console.log);console.log);ts中类的访问类型
  • ts中的访问类型就是基于三个关键字:privateprotected以及pubilc这三种访问类型。看例子,先定义一个类,然后用这个类的对象,进行赋值:
class Person{ name:string}const person=new Person;person.name='tom';console.logpubilc
  • 运行可以看到正常的输出内容,这是因为如果不对name的访问属性进行定义,那么他的默认属性就是pubilc,从字面意思来看,它的意思就是公用的,允许在类的内部和外部被调用。

class Person{public name:string}const person=new Person;person.name='tom';console.logprivate
  • private的属性意思就是只允许在类的内部调用,不能在外部调用
class Person{ private name:string; public say{ console.log; }}const person=new Person;person.name='tom';//报错console.log//报错protected
  • protected允许在类内以及继承的子类中使用,把刚刚的name改成protected属性,这时候在外部就会报错,这时候再写一个继承,代码如下:
class Person{ protected name:string; public say{ console.log; }}const person=new Person;person.name='tom';//报错console.log//报错class NewPerson extends Person{ public back{ console.log }}const newperson=new NewPerson;newperson.back//正常类的构造函数
  • 首先新建一个类:Person,定义一个name,并在new的时候进行参数传递,然后打印出来,这时候我们就可以使用构造函数constructor :
class Person{ pubilc name:string; constructor{ this.name=name }};const person=new Person;console.log;
  • 可以看到可以打印出来,但是上面写法有点麻烦,还可以再进行简化:
class Person{ constructor{}};const person=new Person;console.log;类继承中的构造器写法
  • 普通的书写方法上面已经演示了,在子类中使用构造函数需要用super调用父类的构造函数,直接看代码:
class Person{ constructor{}};class Teacher extends Person{ constructor{ super }};const teacher=new Teacher;console.log;ts中类的Getter、Setter、static以及readonly
  • 在上面中提到了访问类型private,它的最大用处就是封装一个书写,然后通过GetterSetter去访问和修改:
class Person{ constructor{ }}
  • 如果想让别人知道,就可以使用Getter来实现,他并不是一个方法,只是一个属性:
class Person{ constructor{ }; get age{ return this._age }};const person=new Person;console.log
  • 这时候你可能会觉得这不是多此一举吗?但在Getter中可以对 _age进行处理:
class Person{ constructor{ }; get age{ return this._age-10 }};const person=new Person;console.log
  • 既然 _age是私有的,我们无法进行改变,这时候就可以用Setter进行改变:
class Person{ constructor{ }; get age{ return this._age } set age{ this._age=age }};const person=new Person;person.age=20;console.log
  • 在类中,如果想用这个类的实例,就必须先进行new操作,但有没有一种方法不需要new就可以?
//常规方法 class Person{ say{ return 'say hello' }};const person=new Person;console.log);
  • 在ts中,我们不想new的话可以这么写:
class Person{static say{ return 'say hello' }};console.log)
  • readonly在初始化后赋值,以后就不能进行修改
class Person{ constructor{}}let p=new Person;p.name='bob'//报错console.log;类的抽象类
  • abstract 用于定义抽象类和其中的抽象方法。它有几个特点:
  • 抽象类是不允许实例化的
//错误演示abstract class Person { public abstract say}const tom=new Person//无法创建抽象类的实例
  • 抽象类中的抽象方法必须被子类实现:
//错误演示abstract class Person { abstract say{ console.log }}class Tom extends Person{ say{ console.log }};//正确方法abstract class Person { abstract say}class Tom extends Person{ say{ console.log }};tsconfig.json配置生成
  • 我们可以通过tsc --init去生成ts配置文件:
tsc --init //终端执行编译
  • 会生成一个tsconfig.json文件,我们在ts文件中可以随便写点什么:
//测试tsconfig.jsonconst test:string='tsconfig.json';
  • 然后打开tsconfig.json文件,找到complilerOptions属性下的removeComments:true(这个配置是编译后不输出注释),取消掉注释,然后执行命令:
tsc
  • 这时候打开生成的js文件,发现没有注释,说明成功。
include 、exclude 和 files
  • 如果有多个ts文件,只想编译一个可以在ts配置项中加入include
"include":["text.ts"],
  • 如果想除了某个文件不编译,剩下的都编译,可以使用exclude
"exclude":["text.ts"],
  • filesinclude没有什么区别:
"files":["text.ts"],compilerOptions配置removeComments
  • 这个配置意思就是编译后不输出注释
strict
  • 这个设置为true,就代表严格执行ts语法,要严格按照ts语法来编写。
noImplicitAny
  • 允许你的注解类型 any 不用特意表明,如果此时设置了true,看例子:
//这时候编译会报错function test { return name;}//正确 function test { return name;}strictNullChecks
  • 意思就是,不强制检查null类型,此时如果配置为true看例子:
//此时就不会报错const test: string = null;outDir和rootDir
  • 此项配置是来指定文件目录和打包后存放目录,rootDir为文件目录,outDir为打包后保存的目录
{ "outDir": "./build" , "rootDir": "./src" ,}编译ES6语法
  • 可以使用targetallowJs,target默认为true
"target":'es5' , // 这一项默认是开启的,你必须要保证它的开启,才能转换成功"allowJs":true, // 这个配置项的意思是联通sourceMap
  • sourceMap 简单说,Source map 就是一个信息文件,里面储存着位置信息。

    也就是说,转换后的代码的每一个位置,所对应的转换前的位置。有了它,出错的时候,除错工具将直接显示原始代码,而不是转换后的代码。这无疑给开发者带来了很大方便。

noUnusedLocals
  • 设置noUnusedLocals为true,编译代码:
const name:tring='111';export const age = "text";
  • 这时候就会报错,因为有name变量没有使用。

更多
  • 更多可以查看 配置查询网站
联合类型和类型保护联合类型
  • 联合类型的意思就是允许一个类型有两种或者两种以上的类型:
interface Test{ name:string; say:=>{ }}interface Test2{ name:string; call:=>{};}function Tom{ console.log}
  • 如果此时修改一下方法:
function Tom{ fun.say}//报错
  • 这是因为只能访问两个类型的共有方法。
类型保护-类型断言
  • 上面的方法,如果修改完报错,这时候我们可以用as来判断:
interface Test { text: boolean; say: void}interface Test2 { text: boolean; skill:string}function judgeWho { if { .skill; }else{ .say; }}const a={ text:true, skill:function:void{ console.log }, say:function:void{ console.log }}judgeWho //1类型保护-in语法
  • in方法与断言比较类似,使用方法如下:
interface Person{ name:string; say:=>{ }}interface Person2{ name:string; todo:=>{ }};function tom{ if{ val.todo }else{ val.say }}类型保护-typeof语法
  • 可以用typeof方法来判断:
function add{ if{ return name+'---'+name2 }else{ return name+name2 }}add类型保护-instanecof语法
  • 如果要保护类型是一个对象,就可以使用instanceof
class NumObject{ num:number}function numbers{ if{ return num1.num+num2.num }}Enum枚举类型
  • 我们平时会有这种写法:
function getName{ if{ return 'one' }else if{ return 'two' }else{ return 'three' }}console.log)
  • 这么写可能有点麻烦,阅读起来还是有点麻烦,这时候可以这么写:
const Status={ ONE:0, TWO:1, THREE:3}function getName{ if{ return 'one' }else if{ return 'two' }else{ return 'three' }}console.log);
  • 这时候我们的枚举就要上场了:
enum Status{ ONE, TWO, THREE}function getName{ if{ return 'one' }else if{ return 'two' }else{ return 'three' }}console.log);
  • 一样也可以输出,因为枚举是有对应数字值的,默认从0开始,当然也可以改变:
enum Status{ ONE=1, TWO,//2 THREE//3}
  • 也可以进行返查操作:
enum Status{ ONE, TWO, THREE}function getName{ if{ return 'one' }else if{ return 'two' }else{ return 'three' }}console.log;泛型
  • 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
在函数中使用
  • 我们先编写一个函数:
function add{ return `${one}${two}`}console.log)
  • 这时候我们希望参数更加灵活一些,两个参数为number或者string:
function add{ return `${one}${two}`}console.log)
  • 这么书写有些麻烦,这时候就可以使用泛型:
function add{ return `${one}${two}`}console.log)
  • 在使用中,泛型通常用 来进行表示。泛型可以有多个吗?当然可以:
function add{ return `${one}${two}`}console.log)
  • 同时泛型也支持类型推断:
function add{ return `${one}${two}`}console.log)在类中使用
  • 首先先写一个类,且接受参数为一个数组,数组里面存放string类型的数据:
class List { constructor {}; getItem:string{ return this.list[index] }};const list=new List;console.log)
  • 这时候如果我们传递数组时候里面又想放数字怎么办:
class List { constructor {}; getItem:string|number{ return this.list[index] }};const list=new List;console.log)
  • 这么写就比较复杂了,这时候就可以使用泛型来简化我们的代码:
class List{ constructor {}; getItem:T{ return this.list[index] }};const list=new List;console.log)
  • 发现上面的代码没有报错?因为类型推论,所以不会报错,严格意义上应该new的时候加上类型:
const list=new List;
  • 还有一种场景,传递过来是一个数组对象,这时候可以通过继承来解决:
interface People{ name:string}class List{ constructor {}; getItem:string{ return this.list[index].name }};const list=new List;console.log)泛型约束
  • 上面例子中,泛型可以为任意值,但有时候我们希望还是能稍微约束一下:
function list{ return `${name}`}console.log)class List { constructor { }; getItem:T{ return this.list[index] }}const list=new Listconsole.log)Namespace命名空间新建一个ts项目
  • 首先,我们建立一个项目文件,然后npm init -y生成package.json文件,然后再tsc -init生成ts配置文件。

  • 在根目录下新建index.html文件,再建立一个srcbulid目录,在src目录下新建一个index.js
  • 配置tsconfig.json文件,设置入口和输出目录(outDir和rootDir)。
  • 打开index.html,引入js文件:
  • 在新建的ts文件中随便写点什么:
console.log;
  • 然后tsc编译一下,打开控制台,我们就可以看到了
编写一个小组件
  • 在我们刚刚建立的index.ts文件,写一个headercontentfooter组件:
class Header { constructor { const elem = document.createElement; elem.innerText = "This is Header"; document.body.appendChild; }}class Content { constructor { const elem = document.createElement; elem.innerText = "This is Content"; document.body.appendChild; }}class Footer { constructor { const elem = document.createElement; elem.innerText = "This is Footer"; document.body.appendChild; }}class Page { constructor { new Header; new Content; new Footer; }}
  • 然后在index.html中加一行js代码:
  • 这时候我们可以看到内容正常输出,但有一个问题,我们的Headercontentfooter都暴露了出来,并不是只暴露一个page,这时候我们的命名空间就派上了用场:
命名空间
  • 命名空间声明的关键词是namespace 比如声明一个namespace Home,需要暴露出去的类,可以使用export关键词,这样只有暴漏出去的类是全局的,其他的不会再生成全局污染了。

 
友情链接
鄂ICP备19019357号-22