ts 接口兼容性,跟ts类型没有关系,只跟属性有关系
namespace a {//接口的兼容性interface Animal {name: string;age: number;}interface Person {name: string;age: number;speak: (words: string) => void}function getName(animal: Animal): string {return animal.name;}let p: Person = {name: 'aaa',age: 10,speak() { }}console.log(getName(p));//基本类型的兼容性//可以把一个具体的值赋值给另一个 更广泛的类型let num: string | number;let str: string = "string";num = str;let num2: {toString(): string}let str2: string = "asda";//这里只要赋值的变量有tostring方法就可以,也可以是另一个多有个值的对象,//只要有tostring方法就可以num = str2;}//类的兼容//跟 类型无关 ,跟属性有关,属性多于申明的 就可以值namespace b {class Animal {name: string}class Bird extends Animal {// swing: number}let a: Animal;a = new Bird();let b: Bird;b = new Animal();b = { name: 'asd' }; //不管这个对象的具体类型,只要属性有就可以}namespace c {//函数兼容性//函数兼容性比较参数//参数可以比之前少但是不能多//返回值可以比之前多,但是不能比之前少type sunFunction = (a: number, b: number) => number;let sum: sunFunction;function f1(a: number, b: number): number {return a;}sum = f1;function f2(a: number): number {return a;}sum = f2;function f3(): number {return 1;}sum = f3;function f4(a: number, b: number, c: number): number {return a;}// sum = f4;//返回值少了不可以,多了可以type GetPerson = () => { name: string, age: string };let getPerson: GetPerson;function g1() {return { name: '23', age: '12' };}getPerson = g1;function g2() {return { name: '23' };}// getPerson = g2; // 少了不行function g3() {return { name: '23', age: '12', data: '123' };}getPerson = g3; // 少了不行,多了可以}namespace d {//函数参数的协变//参数双向协定(但是现在实现不了了)//参数接受类型可以比之前多一些,但是不能比之前少,满足不了需求type logFunc = (a: number | string) => void;let log: logFunc;function log1(a: number | string | boolean) {console.log(a);}log = log1;//泛型的兼容性//判断兼容性的时候,先判断具体的类型,在进行兼容性判断//要看属性的兼容性,接口的值是空的时候是可以赋值的//但是如果 接口返回值不同时,就会报错interface Empty<T> {data: T}let x: Empty<string>; //{data:string}let y: Empty<number>; //{data:number}// x = y;//枚举的兼容性enum Colors {Red, Yellow}let c: Colors;c = Colors.Red;//0c = 1;let d: number;d = Colors.Yellow;//1}
类型保护
namespace a {//类型保护 就是更精确的知道是哪种类型//ts会根据你的代码 查看你当前面的数据类型function double(input: string | number | boolean) {if (typeof input === 'string') {input.toLocaleLowerCase()} else if (typeof input === 'number') {input.toFixed();} else {input;}}class Animal {public name: string = 'asd';}class Birder extends Animal {public swing: string = "asd1";}function getName(a: Animal) {if (a instanceof Birder) {a.swing} else {a.name}}//null保护//如果在函数内部去兼容了null,有可能ts 因为作用域问题,识别不了//所以可以加一个非空断言function getFirstLetter(s: string | null) {// if (s === null) {// s = '';// }function ensure() {s = s || '';}ensure()// s = s || '';return s!.charAt(0);}//链判断运算符//1是先检查一种类型是不是存在,然后在访问该属性的运算符号,//2如果运算符左侧的操作数?.计算结果为undefind 或 null,则表达式//返回值为undefined ,否则正常触发目标的属性访问,方法或者函数调用let a1 = { b: 1, c: () => { } };let a2 = () => { };//先判断a是否为null或者undefindconsole.log(a1 ? a1.b : a1);a1?.['b'];a1?.c();a2?.();//可辨识的联合类型//1.就是利用联合 类型中的共有字段进行类型保护的一种技巧//2.相同字段的不同取值就是可辨识interface WarningButton {//接口class 的值是一个字符串,表示他也是一个类型//意思就是一个字面量 类型class: 'Warning',text1: '修改'}interface DangerButton {class: 'Danger',text2: '删除'}type Button = WarningButton | DangerButton;function getButton(button: Button) {if (button.class === "Warning") {button.text1;} else {button.text2;}}//判断是不是有哪些属性interface Bird {swing: number}interface Dog {leg: number}function getNumber(x: Bird | Dog) {//判断属性值是不是在x 内if ('swing' in x) {x.swing;} else {x.leg;}}}//自定义的类型保护//ts的类型保护实际就是一些表达式,会在运行时检查类型信息,以确保//在某个作用域里的类型时符合预期的//要自定义一个类型保护,只需要简单的为这个类型保护定义一个函数即可,//这个函数的返回值是一个类型谓词//类型谓词的语法就是: 当前函数某个参数参数 is Typenamespace b {interface Bird {name1: '1'leg: number}interface Dog {name2: '2'leg: number}//自定义的类型保护器function isBird(x: Bird | Dog): x is Bird {//自定义一个规则return x.leg === 2;}function getAnimal(x: Bird | Dog) {if (isBird(x)) {x.leg; //x就是鸟x.name1} else {x.name2 //就不是鸟}}let x: Bird = { name1: '1', leg: 2 };getAnimal(x);}
问题
1.一个函数可以绑定多个泛型么?
function swap
}
2.接口数据类型定义为什么有时候是冒号,有时候是=>
//定义数据类型就是: ,但是定义函数=>表示函数 后跟返回值
interface Bird {
name: string;
fly(): void;
speak: (words: string) => void;
}
3.类型兼容
//就是值在日常编程中 重新赋值不报错,也就是类型自动可以转化
