[TOC] >[success] # 类型类型推论和兼容 ~~~ 1.'类型推论':TypeScript里,在有些没有明确指出类型的地方,类型推论会帮助提供类型 2.'类型兼容':'TypeScript'的类型系统允许某些在编译阶段无法确认其安全性的操作。当一个类型系统具此属性时, 被当做是“不可靠”的。我的理解就是'你我本无缘都靠长得像' ~~~ >[info] ## 类型推论 ~~~ 1.TypeScript里,在有些没有明确指出类型的地方,类型推论会帮助提供类型 ~~~ >[danger] ##### 通用类型 ~~~ 1.ts 会根据赋值做出类型推论 ~~~ ~~~ let name1 = 'wang' // 等同于 let name1:string = 'wang' let arr = [1,'a'] // let arr: (number|string)[] = [1,'a'] arr = [1, 'a', 1] // arr = [1, 'a', true] // 报错 // 如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查: let myFavoriteNumber; myFavoriteNumber = 'seven'; myFavoriteNumber = 7; ~~~ >[danger] ##### 上下文归类 * 这里有个小疑问后期调查一下 ~~~ // 正常情况下如果没有给a赋值类型,a会被自动推断类型为MouseEvent // 但是现在没有 需看时候后期需要配置什么 window.onmousedown = (a)=> { console.log(11) } ~~~ * 如果我们不知道我们参数的类型是什么,又不想使用any,可以如图查看 ![](https://img.kancloud.cn/65/47/6547911c1a638af35ef4a9b832706cd6_875x258.png) ~~~ window.onmousedown = (a:MouseEvent)=> { console.log(11) } ~~~ >[info] ## 类型兼容 ~~~ 1.'TypeScript'的类型系统允许某些在编译阶段无法确认其安全性的操作。当一个类型系统具此属性时, 被当做是“不可靠”的。我的理解就是'你我本无缘都靠长得像' ~~~ >[danger] ##### 基本规则 ~~~ 1.下面有个案例'infos'的类型已经定义好是一个包含'name'字段,我们以把只具有一个'name'字段的属性'infos1' 赋值给infos是可以的,在吧infos2 这种只要包含'name'字段的对象赋值也是可以的。但是'infos3'这种不具备包含 'name'字段的对象赋值就发现报错 3.'总结':'类型兼容性 如果x要兼容y,那么y至少具有与x相同的属性',你可以把'多的赋值给少的',但是不能'把少'的赋值 给'多的' ~~~ ~~~ interface Info{ name:string } let infos:Info const infos1 = { name: 'w' } const infos2 = {name:'w',age:12} const infos3 = { age: 18 } infos = infos1 infos = infos2 // infos2 = infos // 报错 少的赋值给多的 // infos = infos3 // 报错的 ~~~ * 注意我们上面案例是 两种变量相互赋值 ~~~ 1.不是下面这种定义了规定类型,赋值后却不按照规定类型赋值 2.'注意':上面是两个变量相互赋值,下面这个是对定义变量赋值不要搞错 ~~~ ~~~ interface Info{ name:string } // let infos:info = {name:'w',age:12} // 报错的 // let infos:info // infos = {name:'w',age:12} // 报错 ~~~ >[danger] ##### 函数兼容 -- 函数参数 ~~~ 1.参数个数一致,类型不同,是不能相互赋值的 2.参数个数不一致,相同类型参数的位置也不一致,是不可以相互赋值的 3.参数个数不一致,相同类型参数的位置一致,可以相互赋值,但是'只能把少的赋值给多的' ~~~ * 首先参数个数一致,类型不同 ~~~ let xx = (a: number) => 0 let yy = (a: string) => 0 // xx = yy // 报错参数类型不一致 ~~~ * 参数个数不一致,相同类型参数的位置也不一致 ~~~ let x = (c: number) => 0 let y = (a: string, b: number) => 0 // xx = yy // 报错 ~~~ * 参数个数不一致,相同类型参数的位置一致,可以相互赋值,但是'只能把少的赋值给多的 ~~~ 1.解释为什么只能把少的赋值给多的,你把少的赋值给多,多的那个没被赋值的参数相当于'undefind' 没有影响, 但是你把多的赋值给少的,少的无缘无故多了一个参数那就报错了 ~~~ ~~~ let x = (a: number) => 0 let y = (a: number,b:string) => 0 y=x // 把少的 给多的,多的可以只用一个参数另一不用 // x = y // 把多的参数,赋值给少参数,因为x定义只有一个a,你多给他一个b他也用不了 ~~~ >[danger] ##### 函数兼容 -- 剩余参数 ~~~ 1.当一个函数有剩余参数时,它被当做无限个可选参数 ~~~ ~~~ const getSum = (nlist:number[],callback:(...args:number[])=>number)=>{ callback(...nlist) } getSum([1,2,3],(...args:number[])=>{ const sum = args.reduce((a, b) => a + b) console.log(sum) // 6 return sum }) getSum([1, 2, 3], (n1:number,n2:number) => { console.log(n1+n2) return n1+n2 }) ~~~ >[danger] ##### 函数兼容 -- 函数参数双向协变 ~~~ 1.当A的参数类型不确定,B 的参数类型为A中不确定参数类型中的一个。可以吧多类型赋值给少类型的 ~~~ ~~~ let funcA = (arg1: number | string) => { } let funcB = (arg1: number ) => { } // funcA = funcB // 错误的 funcB = funcA ~~~ >[danger] ##### 函数兼容 -- 返回值类型 ~~~ 1.函数返回类型可以把少的赋值给多的,多的不能赋值给少的 ~~~ ~~~ let funcTypeA = (): string | number => 0 let funcTypeB = (): number => 0 funcTypeA = funcTypeB // funcTypeB = funcTypeA // 报错 ~~~ >[danger] ##### 函数兼容 -- 函数的重载 ~~~ 1.重载类型不一致怎么赋值都是错 ~~~ ~~~ function merge(n1: number, n2: number): number function merge(n1: string, n2: string): string // 虽然是any 但是只能是 string 或者 number function merge(n1:any,n2:any):any{ return n1+n2 } function sum(n1: number, n2: number): number function sum(n1: any, n2: any): any { return n1 + n2 } // 问题重载类型不一致怎么赋值都是错 // merge = sum // 报错 // sum = merge // 报错 ~~~ >[danger] ##### 枚举的兼容 ~~~ 1.不同枚举类型是不兼容的 ~~~ ~~~ enum StatusEnum{ Off, On } enum AnimalEnum{ Dog, Cat } let s = StatusEnum.Off // s = AnimalEnum.Dog // 不同枚举类型是不兼容的 ~~~ >[danger] ##### 类 ~~~ 1.类有静态部分和实例部分的类型。 比较两个类类型的对象时,只有实例的成员会被比较。 静态成员和构造函数不在比较的范围内 2.向下面的案例'AnimalClass ' 和'PeopleClass',中 因为static 是静态类方法所以他们age属性是不影响他们相互赋值 ,比较的都是实例成员,也因此'FoodIsClass ' 的name属性类型和另外两个不一致不能相互赋值 ~~~ ~~~ class AnimalClass { public static age: number constructor(public name: string) {} } class PeopleClass { public static age: string constructor(public name: string) {} } class FoodIsClass { constructor(public name: number) {} } let animal: AnimalClass = new AnimalClass('w') let people: PeopleClass = new PeopleClass('w') let food: FoodIsClass = new FoodIsClass(1) people = animal // animal = food // 报错 ~~~ * 类的私有成员和受保护成员? 后续看 >[danger] ##### 泛型 ~~~ 1.如果定义接口里面没东西,那么泛型类型可以交叉赋值,如果有了东西类型不一致就报错了 ~~~ ~~~ interface Empty<T> { } let x: Empty<number>; let y: Empty<string>; x = y; interface NotEmpty<T> { data: T; } let x: NotEmpty<number>; let y: NotEmpty<string>; x = y; // Error, because x and y are not compatible ~~~