TS的基本数据类型
-
null和undefined只有本身
-
function:
-
声明的函数在调用的时候,参数个数要和声名的时候的参数个数保持一致,并且要保持类型的相同
-
//没有返回值的函数可以用void声明 const fn1 = (param1:string,param2:number): void => { console.log("我是没有返回值的箭头函数"); }; function f2(param1:string,param2:number):void{ console.log("我是没有返回值的普通函数"); } //有返回值的箭头函数声明是这样的 const fn3 = (): string => { return "马冬梅=>" }; //有返回值的普通函数声明是这样的 function f4():string{ return "马冬梅fn" } //函数表达式的双向限定 //上述fn1其实只对=右侧做了限制,对左侧并没有 //完善一点,可以这样 => 用来表示函数的定义,左输入类型,需要用括号括起来,右输出类型 const fn1:(param1:string,param2:number)=>void = (param1:string,param2:number): void => { console.log("我是没有返回值的箭头函数"); }; // 函数的可选参数 // 注意可选参数要在确定参数后 function f5(name:string,age?:number):string{ //带问号表示可选参数 return "马冬梅fn" } //函数参数默认值 function f6(name:string,age:number=18):string{ return `${name}--${age}` } //此时可选参数不必一定在确定参数后,但是调用有问题 function f7(name:string,desc?:string,age:number=18):string{ return `${name}--${age}--${desc}` } //剩余参数,不确定参数有多少个的时候就会用到剩余参数 function f8(...args:number[]):number[]{ return args } console.log(f8(1,2,3,4,5))//[1,2,3,4,5] // 函数重载 重载是方法名字相同,而参数不同,返回类型可以相同也可以不同。 每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。 参数类型不同: function disp(string):void; function disp(number):void; 参数数量不同: function disp(n1:number):void; function disp(x:number,y:number):void; 参数类型顺序不同: function disp(n1:number,s1:string):void; function disp(s:string,n:number):void;
-
-
void声名变量
-
void也可以用来声名变量,但是只能用在
undefined
身上,null
也不行,除非做了配置 -
symbol
-
bigint (兼容性不是特别的好)
-
任意值(any/unknown)用来表示允许赋值为任意类型
-
数组
//像java中的集合+泛型,List<String> arr=new ArrayList(); const arr1: Array<string> = ["马","冬","梅"] //类型后+[],java中也是如此:String [] arr = {"马","冬","梅"}; const arr2: string[] = ["马","冬","梅"] //数组的项中不允许出现其他的类型 const arr3: string[] = ["马","冬","梅",1024]//报错 1024非字符串 // any[] 类型的数组可以不同 const anyArray: any[] = [1, 'hh', false] // 联合类型数组 const arr: number[]|string[] arr = [1, 2, 3] // 数字数组 arr = ['1', '2', '3'] //字符串数组 //解构数组 const array: number[] = [1, 2]; const [x, y] = array; // x = 2, y = 2 // 等价于 const x = array[0]; const y = array[1];
-
元组:TS中的元组与JS的数组很像,可以存储不同类型的值
ts允许向元组中使用数组的push方法插入新元素(但不允许访问),不然就是越界了
-
枚举:枚举相当于可以由值得到它的名字,这种感觉像对象的键值对
-
枚举类型也确实属于对象类型
-
ts只支持基于数字和字符串的枚举
-
对于基于数字的枚举类型支持键值对的反向映射 key<=>value
-
基于字符串的不可以反向映射?当然不可以,就是纯js对象
-
数组枚举–默认增长
enum Language{ java, node, php, python } //可以按值访问 console.log(Language[0])//java //也可以按键访问 console.log(Language["java"])//0 //打印结构如下 console.log(Language); { '0': 'java', '1': 'node', '2': 'php', '3': 'python', java: 0, node: 1, php: 2, python: 3 } //编译后代码如下 IIFE传参的形式 "use strict"; var Language; (function (Language) { Language[Language["java"] = 0] = "java"; Language[Language["node"] = 1] = "node"; Language[Language["php"] = 2] = "php"; Language[Language["python"] = 3] = "python"; })(Language || (Language = {})); console.log(Language); //# sourceMappingURL=index.js.map //可以看到内层赋值生成的是 { java: 0, node: 1, php: 2, python: 3 } //外层赋值生成的是 { '0': 'java', '1': 'node', '2': 'php', '3': 'python', }
-
数字枚举–自定义增长,我们可以手动的设置相关的值来进行增长,当然,未设置的值会根据上下文增长
enum Language{ java=5, node, php, python } //打印一下 console.log(Language) { '5': 'java', '6': 'node', '7': 'php', '8': 'python', java: 5, node: 6, php: 7, python: 8 } //当然你也可以全部手动指定每个值,不连续也可以 enum Language{ java=100, node=101, php=103, python=104 } enum Language{ java=5, node, php, python } //打印一下 console.log(Language) { '5': 'java', '6': 'node', '7': 'php', '8': 'python', java: 5, node: 6, php: 7, python: 8 } //当然你也可以全部手动指定每个值,不连续也可以 enum Language{ java=100, node=101, php=103, python=104 }
-
字符串枚举:其实就是把上述数字枚举的值换成字符串,但结构有些不同,枚举属于对象类型
-
-
对象:TS在对象的使用上存在着一些限制,必须是特定类型的实例,常常配合interface使用
-
基本使用:
//创建一个空对象 const obj:object={}; //也许你想这样给对象增加属性 //但是不行,会报错,因为最初是一个空对象,自然没有这个name属性 obj.name="tom" //这就需要好用的interface出场了 //如果你用过java,那应该清楚接口是一套待实现的规范 //和元组规范类似,实例属性与声明类型的属性数量和名称严格一致,不可多不可少 interface User{ name:string } const u1:User={ name:"马东梅" } //报错,多属性 const u2:User={ name:"马东梅", age:24 } //报错,少属性 const u3:User={} //若属性值为函数,也需要在接口中声明 interface Person{ name:string, say: (something: string) => string } const p:Person={ name:"jack", say: (something: string) => something } console.log(p.say("hello"))//hello
-
可选属性,有些时候我们希望某些属性是可选的,这时候我们可以使用
?
进行修饰interface Stu{ name:string, desc?:string } //此时缺少desc属性也是可以的,因为它是可选属性 const s:Stu={ name:"tom" }
-
任意属性:有时候我们允许任意属性的添加
interface Stu { name: string; sno?: number; [prop: string]: any; } //这样写ok const s1: Stu = { name: 'Tom', sex: '男' }; //这样写也ok,可选属性没什么影响 const s2: Stu = { name: 'Jack', sex: '男', sno:10010 };
-
接口继承:
-
接口继承就是说接口可以通过其他接口来扩展自己。
Typescript 允许接口继承多个接口。
继承使用关键字 extends。
单接口继承语法格式:
Child_interface_name extends super_interface_name
多接口继承语法格式:
Child_interface_name extends super_interface1_name, super_interface2_name,…,super_interfaceN_name
继承的各个接口使用逗号 , 分隔。
-
单继承实例:
interface Person { age:number } interface Musician extends Person { instrument:string } var drummer = <Musician>{}; drummer.age = 27 drummer.instrument = "Drums" console.log("年龄: "+drummer.age) console.log("喜欢的乐器: "+drummer.instrument)
-
多继承实例
interface IParent1 { v1:number } interface IParent2 { v2:number } interface Child extends IParent1, IParent2 { } var Iobj:Child = { v1:12, v2:23} console.log("value 1: "+Iobj.v1+" value 2: "+Iobj.v2)
-
-
map对象:Map 对象保存键值对,并且能够记住键的原始插入顺序。
Map 相关的函数与属性:
- map.clear() – 移除 Map 对象的所有键/值对 。
- map.set() – 设置键值对,返回该 Map 对象。
- map.get() – 返回键对应的值,如果不存在,则返回 undefined。
- map.has() – 返回一个布尔值,用于判断 Map 中是否包含键对应的值。
- map.delete() – 删除 Map 中的元素,删除成功返回 true,失败返回 false。
- map.size – 返回 Map 对象键/值对的数量。
- map.keys() - 返回一个 Iterator 对象, 包含了 Map 对象中每个元素的键 。
- map.values() – 返回一个新的Iterator对象,包含了Map对象中每个元素的值 。
迭代map
Map 对象中的元素是按顺序插入的,我们可以迭代 Map 对象,每一次迭代返回 [key, value] 数组。
TypeScript使用 for…of 来实现迭代:
-
类型推断
-
ts更严格(定义并且赋值的情况)
虽然ts是js的超集,但是ts有自动的类型推断,所以定义好数据值时候就相当于已经定义好了这个变量的类型
- 定义但是不赋值
如果变量定义的时候没有赋值,不管之后有没有赋值,都会被推断为any类型二完全不被类型检查,但是这不是一个好习惯哦
//这不是什么好习惯,像极了脱缰的野马 //当你试图削弱ts静态类型检查优势的时候,说明你依旧过度依赖js写法 let str; str="lengyuexin" str=1024; str=[] str=false; str={}
类型断言
类型断言可以用来手动指定一个值的类型,即允许变量从一种类型更改为另一种类型。
用法:
1. <类型>值
2. 值 `as` 类型
联合类型
- 联合类型标识取值可以为多种类型中的一种,不同类型使用管道符
|
进行分割,类似于或 - 使用联合类型的属性和方法,一定要记住只有公共的属性和方法才可以被访问,如果不是两个类型共有的属性和方法就会报错,例如
string
和number
两个类型的变量就不能使用.length
这个属性、
类与接口
-
类实现接口
//定义动物类 若有实例属性外部初始化,需要构造函数 class Animal { color: string; constructor(color: string) { this.color = color; } //也可以声明实例方法 yell(str:string):string{ return str } } //*******************// // 以下示例基于最原始的 class Animal {} //将叫声这一行为抽象成接口 interface AnimalYell{ yell():void } //定义动物类 class Animal { } // 定义Mammal类,继承Animal类,实现AnimalYell接口 class Mammal extends Animal implements AnimalYell { yell() { console.log('动物发出叫声'); } } //Dog,Cat类继承父类Mammal,重写yell方法 // 这里也可以直接让Dog,Cat实现AnimalYell接口 //之所以继承,是更大程度的复用父类Mammal的特点(属性和方法) class Dog extends Mammal { yell(){ console.log('汪汪...'); } } class Cat extends Mammal { yell(){ console.log('喵喵...'); } } // 一个类可以实现多个接口 interface AnimalWalk{ walk():void } //Snake实现AnimalWalk,AnimalYell两个接口\ //实现接口要实现每个接口中的方法 //若以下代码缺少yell或walk的实现就会报错 class Snake implements AnimalWalk,AnimalYell{ yell(){ console.log("嘶嘶...") } walk(){ console.log("爬行...") } } new Mammal().yell()//动物发出叫声 new Dog().yell()//汪汪... new Cat().yell()//喵喵... new Snake().yell()//嘶嘶... new Snake().walk()//爬行...
- 接口继承接口
类可以继承,接口也可以。实际上,ts中接口还能继承类,不过一般不用哈
//将手机功能抽象为一个接口 interface BasePhoneFunction { call(): string; //打电话 send(message: string): string[]; //群发短信 } // 在基础功能上,还有其他功能 interface PhoneFunction extends BasePhoneFunction { game(): void; //打游戏 listen(): void; //听音学 watchTV(...tvName:string[]): void; //看电视 note(): string[]; //便签 } class Phone implements PhoneFunction { call() { return "hi, tom,when are we going to coding?"; } send(message: string) { console.log(message); return ["tom", "jack", "july"]; } game(){ console.log("打游戏") } listen(){ console.log("听音乐") } //注意这里的rest参数用法,形参名不必和接口定义的形参名一致 tvName watchTV(...args:string[]){ console.log(`看${args.toString()} `) } note(...args:string[]){ return [...args] } } const p=new Phone() console.log(p.call())//hi, tom,when are we going to coding? p.send("新年快乐") //新年快乐 console.log(p.send("新年快乐"))// 新年快乐 ["tom", "jack", "july"] p.game()//打游戏 p.listen()//听音乐 p.watchTV("琅琊榜","将夜")//看琅琊榜,将夜 console.log(p.note("吃饭","睡觉","打豆豆"))//[ '吃饭', '睡觉', '打豆豆' ]
访问修饰符
- public:public权限最高的,默认就是public,可自由的访问程序里定义的成员
- peivate:子类中访问不到,只能在class中才能被访问,实例访问不到
- protected:子类中可以访问得到,实例访问不到
TS一文弄懂泛型
泛型