🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] >[success] # 子类型都兼容父类型 ~~~ 1.所有的子类型与它的父类型都兼容 ~~~ ~~~ // 案例一 let num: number let one: 1 = 1 num = one // 案例二 IPar 是父接口虽然结构上看比IChild少 // 但是子类型赋值父类型没问题 interface IPar { name: string } interface IChild extends IPar { id: number } let Par: IPar let Child: IChild = { id: 1, name: '12' } Par = Child // Dog 继承了Animal 同理 最后DOG 可以赋值给Animal class Animal { name: string = 'w' } class Dog extends Animal { run() {} } let animal:Animal let dog = new Dog() animal = dog ~~~ >[success] # 结构类型 ~~~ 1.如果x要兼容y,那么y至少具有与x相同的属性',你可以把'多的赋值给少的',但是不能'把少'的赋值 给'多的' ~~~ >[danger] ##### 定义类型方式不同但字段参数类型都相同 ~~~ 1.x要兼容y,那么y至少具有与x相同的属性 满足即下面都能互相兼容 ~~~ ~~~ class A { name = 1 } interface B { name: number } type C = { name: number } // 字面量 const d = { name: 2 } let a: A = d let b: B = a let c: C = b ~~~ >[danger] ##### y 拥有x 所有属性且拥有y不具备属性 ~~~ 1.一个类型不仅拥有另外一个类型全部的属性和方法,还包含其他的属性和方法(如同继承自另外一个类型的子类一样), 那么前者是可以兼容后者的'多的赋值给少的' ~~~ ~~~ class A { name = 1 age = 1 } interface B { name: number } type C = { name: number } // 字面量 const d = { name: 2 } let b: B = new A() let c: C = new A() // 报错 let a: A = d // 报错 少的赋值给多的了 ~~~ >[danger] ##### 对象字面的 freshness 特性 ~~~ 1.上面案例将'多的赋值给少的' 有特例,如果是字面量的对象不能直接兼容 ~~~ * 非字面量的情况完美兼容 ~~~ class A { name = 1 age = 1 } interface B { name: number } let b: B = new A() ~~~ * 字面量情况 ~~~ interface B { name: number } let b: B = { id: 1, name: 1 } // 报错 // 需要先打破freshness 特性,即赋值一次做中转 const a = { id: 1, name: 1 } b = a // ok // 或者使用断言,断言必须是子父关系 将低等级断言给高等级的 // 其实满足之前说到多的可以兼容少的 const c: B = { id: 1, name: 1 } as B // interface B { // name: number // age: number // } // // 这样断言成功因为 { age: 1 } 是B的子集 // const c: B = { age: 1 } as B ~~~ >[success] # 类 ~~~ 1.如果两个类包含私有、受保护的属性和方法,则仅当这些属性和方法源自同一个类,它们才兼容 2.类有静态部分和实例部分的类型。 比较两个类类型的对象时,只有实例的成员会被比较。 静态成员和构造函数不在比较的范围内 ~~~ >[danger] ##### 解释第一条 ~~~ class C1 { name = '1' private id = 1 protected age = 30 } class C2 { name = '2' private id = 1 protected age = 30 } let InstC2: C2 = new C1() // 报错 ~~~ >[danger] ##### 解释第二条 ~~~ 1.向下面的案例'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 // 报错 ~~~ >[success] # 泛型 ~~~ 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 ~~~ >[success] # 函数兼容 -- 函数参数 ~~~ 1.参数个数一致,类型不同,是不能相互赋值的 2.参数个数不一致,相同类型参数的位置也不一致,是不可以相互赋值的 3.参数个数不一致,相同类型参数的位置一致,可以相互赋值,但是'只能把少的赋值给多的' ~~~ >[danger] ##### 首先参数个数一致,类型不同 ~~~ let xx = (a: number) => 0 let yy = (a: string) => 0 // xx = yy // 报错参数类型不一致 ~~~ >[danger] ##### 参数个数不一致,相同类型参数的位置也不一致 ~~~ let x = (c: number) => 0 let y = (a: string, b: number) => 0 // xx = yy // 报错 ~~~ >[danger] ##### 参数个数不一致,相同类型参数的位置一致,可以相互赋值,但是'只能把少的赋值给多的 ~~~ 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 // 报错 ~~~ >[success] # 枚举的类型兼容性 ~~~ 枚举与数字类型相互兼容: enum Status { Ready, Waiting } let status = Status.Ready; let num = 0; status = num; num = status; ~~~