生成器(Builder)
又称建造者模式,该模式是一种创建型设计模式,能够分步骤创建复杂对象。该模式允许使用相同的创建代码生成不同类型和形式的对象。
具体内容请跳转链接查看:设计模式-生成器
for…of 语句
for…of 会遍历可迭代的对象,调用对象上的 Symbol.iterator
方法。(此对象非彼对象,这个对象是指你即将下手的目标)
对象也是不支持的,因为对象没用Symbol.iterator
方法。
type mapKeys = string|number//相当于起别名,在下方使用的时候集合了string与number就会相对方便不少 let set:Set<number> = new Set([1,2,3]) let map:Map<mapKeys,mapKeys> = new Map()//这里断言两个mapKeys,一个对应key,一个对应value map.set('1','小满') map.set('2','看看腿') for (let item of set){ console.log(item) }//打印出1 2 3 for (let item of arr){ console.log(item) }//打印出4 5 6 for (let item of map){ console.log(item) }//打印出['1','小满'] ['2','看看腿'] //其实这就是一个语法糖,将of后面的内容遍历存储到of前面的变量中
跟for in 的区别
for in循环出来的是索引而不是内容,这个应该是最本质的区别了
因为for of会调用底层interator里面那个list的.value
泛型(generic) => (TS -- 14上)
泛型简单来说就是类型变量,在 ts 中存在类型,如 number、string、boolean等。泛型就是使用一个类型变量来表示一种类型,类型值通常是在使用的时候才会设置。泛型的使用场景非常多,可以在函数、类、interface 接口中使用
TypeScript中不建议使用 any 类型,不能保证类型安全,调试时缺乏完整的信息。
TypeScript 可以使用泛型来创建可重用的组件。支持当前数据类型,同时也能支持未来的数据类型。扩展灵活,可以在编译时发现类型错误,从而保证了类型安全。
无泛型用法
//数字类型 function num(A:number,B:number):Array<number>{//Array<number>为希望返回number类型的数组 return [a,b] } num(6,9) //字符串类型 function str(A:string,B:string):Array<string>{//Array<number>为希望返回number类型的数组 return [a,b] } str('小满','穿女装')
一个笨的方法就像上面那样,也就是说 JS 提供多少种类型,就需要复制多少份代码,然后改下类型签名。这对程序员来说是致命的。这种复制粘贴增加了出错的概率,使得代码难以维护,牵一发而动全身。并且将来 JS 新增新的类型,你仍然需要修改代码,也就是说你的代码对修改开放,这样不好。
如果你使用 any 的话,怎么写都是 ok 的, 这就丧失了类型检查的效果。实际上我知道我传给你的是 string,返回来的也一定是 string,而 string 上没有 toFixed 方法,因此需要报错才是我想要的。也就是说我真正想要的效果是:当我用到id的时候,你根据我传给你的类型进行推导
。比如我传入的是 string,但是使用了 number 上的方法,你就应该报错。
使用泛型优化
为了解决上面的这些问题,我们使用泛型对上面的代码进行重构。和我们的定义不同,这里用了一个 类型 T,这个 T 是一个抽象类型,只有在调用的时候才确定它的值,这就不用我们复制粘贴无数份代码了。
其中 T
代表 Type,在定义泛型时通常用作第一个类型变量名称。但实际上 T
可以用任何有效名称代替。除了 T
之外,以下是常见泛型变量代表的意思:
- K(Key):表示对象中的键类型;
- V(Value):表示对象中的值类型;
- E(Element):表示元素类型。
function add<T>(a:T,b:T):Array<T>{//通常定义的时候类型是不明确的,所以一般使用T来定义 return [a,b]; } add<number>(1,2)//1对应a,2对应b、返回的都是number类型 add<string>('1','2')//这个时候,我们只需要改动这个string,传递到上面的时候就会自动推断为string类型了 //甚至我们可以简写 add(1,2) add('1','2')//编辑器会自动推断类型,但最好还是写一下,如果你知道你具体需要的是什么的话 //对泛型进行总结就是:定义前不明确类型,使用的时候再明确类型,能够给我们保留有足够的自由度,又不会像any丧失类型检查的效果 我们也可以使用不同的泛型参数名,只要在数量上和使用方式上能对应上就可以。 function Sub<T,U>(a:T,b:U):Array<T|U> {//这个T跟U随便起名字都行,没有强制规范 const params:Array<T|U> = [a,b] return params } Sub<Boolean,number>(false,1)//我们这里就将其定义为布尔值类型跟数字类型
定义泛型接口
声明接口的时候 在名字后面加一个 <参数>
使用的时候传递类型
interface MyInter<T> { (arg: T): T } function fn<T>(arg: T): T { return arg } let result: MyInter<number> = fn result(123)
对象字面量泛型
let foo: { <T>(arg: T): T } foo = function <T>(arg:T):T { return arg } foo(123)
泛型约束(函数类)
我们期望在一个泛型的变量上面,获取其 length
参数,但是,有的数据类型是没有 length
属性的
function getLegnth<T>(arg:T) { return arg.length } • 这个时候,我们就可以对其进行约束 interface Len{ length:number } function getLegnth<T extends Len>(arg:T) {//使用接口让泛型T继承了Len return arg.length } getLength(1)//这个时候我们这样使用就会提示我们类型"number"的参数不能赋给"Len"的参数 //我们依次对数组、字符串、布尔值都进行尝试,分别为可以、可以、不可以
泛型约束|泛型类(TS -- 14下)
使用 keyof 约束对象
其中使用了 TS 泛型和泛型约束。首先定义了 T 类型并使用 extends 关键字继承 object 类型的子类型,然后使用 keyof 操作符获取 T 类型的所有键,它的返回 类型是联合 类型,最后利用 extends 关键字约束 K 类型必须为 keyof T 联合类型的子类型
function prop<T, K extends keyof T>(obj: T, key: K) { return obj[key] } let o = { a: 1, b: 2, c: 3 } prop(o, 'a') prop(o, 'd') //,我们需要约束一下这个o里面并没有的东西,此时就会报错发现找不到 //通过提示,我门可以看到类型"d"的参数不能赋给类型"a"|"b"|"c"的参数
泛型类
声明方法跟函数类似名称后面定义 <类型>
使用的时候确定类型 new Sub()
//定义泛型的一个类 class Sub<T>{ attr:T[] = []//这里的:只是普通的: add(a:T):T[]{ return [a] } } let s = new Sub<number>()//这里已经使用泛型固定为number了 s.attr = [123]//正常运行 s.attr = ['123']//报错 s.add(123)//也是只能传数字 let str = new Sub<string>()//这里已经使用泛型固定为number了 str.attr = [123]//报错 str.attr = ['123']//正常运行 str.add('123')//也是只能传字符串 console.log(s,str)