经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » TypeScript » 查看文章
TypeScript 学习笔记 — 类型兼容 (十)
来源:cnblogs  作者:Echoyya、  时间:2023/3/27 14:51:27  对本文有异议


TS 是结构类型系统(structural type system),基于结构/形状检查类型,而非类型的名字。

TS 中的兼容性,主要看结构是否兼容。(核心是考虑安全性),结构化的类型系统(又称鸭子类型检查),如两个类型名字不一样但是无法区分
类型兼容性是基于结构子类型的。 结构类型是一种只使用其成员来描述类型的方式。

如果x要兼容y,那么y至少具有与x相同的属性。
这里要检查y是否能赋值给x,编译器检查x中的每个属性,看是否能在y中也找到对应属性。
X 兼容 Y:X(目标类型)= Y(源类型)
简单一句话概括兼容性: 重新赋值不报错(类型自动转化)

一.基本数据类型的兼容性

  1. let temp: string | number;
  2. let num!: number;
  3. temp = num;
  1. let obj: {
  2. toString(): string;
  3. };
  4. let str: string = "yya";
  5. obj = str; // 字符串中具备toString()方法,所以可以进行兼容
  6. obj.toString(); // 安全, 保证使用的时候不会发生异常

二.接口兼容性

接口的兼容性,只要满足接口中所需要的类型即可!(保证你要的,我都有,就行,多了也没关系)

  1. interface IAnimal {
  2. name: string;
  3. age: number;
  4. }
  5. interface IPerson {
  6. name: string;
  7. age: number;
  8. address: string;
  9. }
  10. let animal: IAnimal;
  11. let person: IPerson = {
  12. name: "yya",
  13. age: 18,
  14. address: "beijing",
  15. };
  16. type T2 = IPerson extends IAnimal ? true : false; // true
  17. animal = person; // 子类赋予给父类 兼容

三.函数的兼容性

函数的兼容性主要是比较参数和返回值

参数:赋值函数的参数要少于等于被赋值的函数:也就是说,对应函数的参数来讲,少的参数可以赋予给多的,因为内部实现传了多个可以少用或不用(忽略额外的参数在 JavaScript 里是很常见的)

sum2的每个参数必须能在sum1里找到对应类型的参数。 注意的是参数的名字相同与否无所谓,只看它们的类型sum2的每个参数在sum1中都能找到对应的参数,所以允许赋值。

  1. let sum1 = (a: string, b: string) => a + b;
  2. let sum2 = (a: string) => a;
  3. sum1 = sum2;

举例: Array#forEach给回调函数传 3 个参数:item,index 和 array。 尽管如此,传入一个只使用第一个参数的回调函数也是可以的

  1. type Func<T> = (item: T, index: number, array: any[]) => void;
  2. function forEach<T>(arr: T[], cb: Func<T>) {
  3. for (let i = 0; i < arr.length; i++) {
  4. cb(arr[i], i, arr);
  5. }
  6. }
  7. forEach([1, 2, 3], (item) => {
  8. console.log(item);
  9. });

返回值:

  1. type sum1 = () => string | number;
  2. type sum2 = () => string;
  3. let fn1: sum1;
  4. let fn2!: sum2;
  5. fn1 = fn2;

四.类的兼容性

类与对象字面量和接口差不多,但有一点不同:类有静态部分和实例部分的类型。 比较两个类类型的对象时,只有实例的成员会被比较。 静态成员和构造函数不在比较的范围内。

  1. class Animal {
  2. feet!: number;
  3. constructor(name: string, numFeet: number) {}
  4. }
  5. class Size {
  6. feet!: number;
  7. constructor(numFeet: number) {}
  8. }
  9. let a!: Animal;
  10. let s!: Size;
  11. a = s; // OK
  12. s = a; // OK

类的私有成员和受保护成员

只要有 private 或者 protected 关键字会影响兼容性, 当检查类实例的兼容时,如果目标类型包含一个 private 私有成员,那么源类型必须包含来自同一个类的这个私有成员。 这条规则也适用于包含 protected 受保护成员实例的类型检查。 允许子类赋值给父类,但是不能赋值给其它有同样类型的类。

  1. class A {
  2. private name!: string;
  3. age!: number;
  4. }
  5. class B {
  6. private name!: string;
  7. age!: number;
  8. }
  9. // let a: A = new B(); // error
  10. class Parent {
  11. protected name: string = "zf";
  12. age: number = 11;
  13. }
  14. class Child extends Parent {}
  15. let child: Parent = new Child(); // ok

五.泛型的兼容性

泛型比较的是最终的结果 比较的不是泛型传递的参数
例一:

  1. interface Empty<T> {}
  2. let x: Empty<number>;
  3. let y!: Empty<string>;
  4. type xx = Empty<number> extends Empty<string> ? true : false; // true
  5. x = y; // OK 因为 y 匹配 x 的结构

在例一中,x 和 y 是兼容的,因为它们的结构使用类型参数时并没有什么不同。 把这个例子改变一下,增加一个成员,就能看出是如何工作的了:
例二:

  1. interface NotEmpty<T> {
  2. data: T;
  3. }
  4. let x: NotEmpty<number>;
  5. let y: NotEmpty<string>;
  6. type xx = NotEmpty<number> extends NotEmpty<string> ? true : false; // false
  7. x = y; // Error, 不兼容

对于没指定泛型类型的泛型参数时,会把所有泛型参数当成 any 比较。 然后用结果类型进行比较,就像例一:

  1. let identity = function <T>(x: T): T {};
  2. let reverse = function <U>(y: U): U {};
  3. identity = reverse; // OK, (x: any) => any 匹配 (y: any) => any

六.枚举的兼容性

枚举类型与数字类型兼容,并且数字类型与枚举类型兼容

  1. enum Status {
  2. Pending,
  3. Resolved,
  4. Rejected,
  5. }
  6. let current = Status.Pending;
  7. let num = 0;
  8. current = num;
  9. num = current;

不同枚举类型之间是不兼容的。

  1. enum Status {
  2. Pending,
  3. Resolved,
  4. Rejected,
  5. }
  6. enum Color {
  7. Red,
  8. Blue,
  9. Green,
  10. }
  11. let current = Status.Pending;
  12. let color = Color.Red;
  13. current = color; // 不能将类型“Color.Red”分配给类型“Status”

标称类型简短介绍

类型分为两种 结构化类型(structural type system) 、标称类型(nominal type system)
标称类型: 虽然 BTC,USDT 都是 number 类型,但还是想要用不同的类型表示,且不能互换,数据的值本身没什么区别,安上不同名字就是不同类型,也就是说,标称类型系统中,两个变量是否类型兼容(可以交换赋值)取决于这两个变量显式声明的类型名字是否相同。

  1. class AddType<S> {
  2. private _type!: S;
  3. }
  4. type NewType<T, S extends string> = T & AddType<S>;
  5. type BTC = NewType<number, "btc">; // number + BTC
  6. type USDT = NewType<number, "usdt">; // number + USDT
  7. let btc = 100 as BTC;
  8. let usdt = 100 as USDT;
  9. function getCount(count: USDT) {
  10. return count;
  11. }
  12. getCount(usdt);

原文链接:https://www.cnblogs.com/echoyya/p/17189305.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号