X兼容Y : X(目标类型) = Y(源类型)
interface Named { name: string; } let x: Named; let y = { name: ‘Chirs‘, age: 23 }; x = y; console.log(‘x‘, x); // x { name: ‘Chirs‘, age: 23 } // 这里要检查 y 是否可以赋值给 x,编译器检查 x 中的每个属性,看能否在 y 中也找到对应的属性 // 相反,把 y 赋值给 x 就会报错,因为 x 不具备 age 属性 y = x; // Property ‘age‘ is missing in type ‘Named‘ but required in type ‘{ name: string; age: number; }‘
let s: string = ‘hello‘; s = null; // 由于在 ts 中, null 是所有类型的子类型,也就是说 字符类型兼容null类型,所以可以赋值
interface X { a: any; b: any; } interface Y { a: any; b: any; c: any; } let x: X = { a: 1, b: ‘2‘ } let y: Y = { a: 3, b: 4, c: 5 } // 只要源类型y 具备了 目标类型x 的所有属性,就可以认为 x 兼容 y x = y; console.log(‘x‘, x); // x { a: 3, b: 4, c: 5 }
interface Handler { (x: number, y: number): void } function foo(handler: Handler) { // handler:目标函数 return handler } let h1 = (a: number) => {} // h1:源函数 // 目标函数的参数个数2个 > 源函数参数个数1个 foo(h1); let h2 = (a: number, b: number, c: number) => {} // h1:源函数 // 目标函数的参数个数2个 < 源函数参数个数3个 foo(h2); // 类型“(a: number, b: number, c: number) => void”的参数不能赋给类型“Handler”的参数
interface Handler { (x: number, y: number): void } function foo(handler: Handler) { // handler:目标函数 return handler } let h3 = (a: string) => {} // h3:源函数 // 尽管目标函数的参数个数多余源函数的参数个数,但是参数类型不同 foo(h3); /* 报错信息: 类型“(a: string) => void”的参数不能赋给类型“Handler”的参数 参数“a”和“x” 的类型不兼容 不能将类型“number”分配给类型“string” */
interface Point3D { x: number; y: number; z: number; } interface Point2D { x: number; y: number; } // 函数 p3d 和 p2d 的参数个数都是1,参数类型都是对象 let p3d = (point: Point3D) => {} let p2d = (point: Point2D) => {} // 赋值时,依然采用的是目标函数的参数个数必须大于源函数参数个数,且参数类型相同的原则 p3d = p2d; p2d = p3d; // 想要不报错,需要关闭 tsconfig.json 中的一个配置 strictFunctionTypes
let p = () => ({ name: ‘Bob‘ }) let s = () => ({ name: ‘Bob‘, age: 23 }) // p 作为目标函数,s 作为源函数时,目标函数的返回值是源函数返回值的子类型 p = s; s = p; // 不能将类型“() => { name: string; }”分配给类型“() => { name: string; age: number; }”
// 固定参数 let a = (x: number, y: number) => {}; // 可选参数 let b = (x?: number, y?: number) => {}; // 剩余参数 let c = (...args: number[]) => {}; // 固定参数 兼容 可选参数和剩余参数 a = b; a = c; // 可选参数 不兼容 固定参数和剩余参数 (可将 strictFunctionTypes 设为false 实现兼容) b = a; b = c; // 剩余参数 兼容 固定参数和可选参数 c = a; c = b;
// 源函数 function overload(x: number, y: number): number; function overload(x: string, y: string): string; // 目标函数 function overload(x: any, y: any): any{ };
// Error1: 目标函数的参数个数 少于 源函数的参数 // 源函数 function overload(x: number, y: number): number; // This overload signature is not compatible with its implementation signature function overload(x: string, y: string): string; // 目标函数 function overload(x: any, y: any, z: any): any{ }; // Error2: 目标函数和源函数的返回值类型不兼容 // 源函数 function overload(x: number, y: number): number; // This overload signature is not compatible with its implementation signature function overload(x: string, y: string): string; // 目标函数 function overload(x: any, y: any) { };
enum Color { Red, Green, Pink }; enum Fruit { Apple, Banana, Orange }; // 枚举类型和数字类型相互兼容 let fruit: Fruit.Apple = 4; let num: number = Color.Red; // 相同枚举类型之间不兼容 let c: Color.Green = Color.Red; // 不能将类型“Color.Red”分配给类型“Color.Green” // 不同枚举类型之间不兼容 let color: Color.Pink = Fruit.Orange; // 不能将类型“Fruit.Orange”分配给类型“Color.Pink”
class A { id: number = 1; constructor(p: number, q: number) {} } class B { static s: number = 1; id: number = 2; constructor(p: number) {} } let aa = new A(3, 6); let bb = new B(8); // 两个类都含有相同的实例成员 number 类型的id,尽管构造函数不同,依然相互兼容 aa = bb; bb == aa;
class A { id: number = 1; private name: string = ‘hello‘; constructor(p: number, q: number) {} } class B { static s: number = 1; id: number = 2; private name: string = ‘hello‘; constructor(p: number) {} } let aa = new A(3, 6); let bb = new B(8); // 在上例的基础上各自添加了相同的 私有成员name,就无法兼容了 aa = bb; bb == aa; // 均报错:不能将类型“B”分配给类型“A”,类型具有私有属性“name”的单独声明
class A { id: number = 1; private name: string = ‘hello‘; constructor(p: number, q: number) {} } class SubA extends A {} let aa = new A(3, 6); let child = new SubA(1, 2) // 就算包含私有成员属性,但是父类和子类的实例可以相互兼容 aa = child; child == aa;
// demo 1 interface Empty<T> {}; let a: Empty<string> = {}; let b: Empty<number> = {}; a = b; b = a; // demo 2 let log1 = <T>(x: T): T => { console.log(‘x‘); return x } let log2 = <U>(y: U): U => { console.log(‘y‘); return y; } log1 = log2;
interface NotEmpty<T> { value: T; }; let a: NotEmpty<string> = { value: ‘string‘ }; let b: NotEmpty<number> = { value: 123 }; a = b; // 不能将类型“NotEmpty<number>”分配给类型“NotEmpty<string>”
原文:https://www.cnblogs.com/rogerwu/p/12205678.html