Typescript 实战 --- (7)类型兼容性
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>”
二、类型保护
enum Type { Strong, Weak }
class Java {
helloJava() {
console.log('Hello Java')
}
}
class JavaScript {
helloJavaScript() {
console.log('Hello JavaScript')
}
}
function getLanguage(type: Type) {
let lang = type === Type.Strong ? new Java() : new JavaScript();
// Error:类型“Java | JavaScript”上不存在属性“helloJava”
if(lang.helloJava) {
lang.helloJava() // Error:类型“JavaScript”上不存在属性“helloJava”
} else {
lang.helloJavaScript() // Error:类型“Java”上不存在属性“helloJavaScript”
}
return lang;
}
function getLanguage(type: Type) {
let lang = type === Type.Strong ? new Java() : new JavaScript();
// 使用类型断言
if((lang as Java).helloJava) {
(lang as Java).helloJava()
} else {
(lang as JavaScript).helloJavaScript()
}
return lang;
}
getLanguage(Type.Strong); // Hello Java
function getLanguage(type: Type) {
let lang = type === Type.Strong ? new Java() : new JavaScript();
// instanceOf
if(lang instanceof Java) {
lang.helloJava()
} else {
lang.helloJavaScript()
}
return lang;
}
enum Type { Strong, Weak }
// 添加一个实例属性,同时要添加构造器,否则在实例对象上还是找不到那个属性
class Java {
java: any;
constructor(java: any) {
this.java = java;
}
helloJava() {
console.log('Hello Java')
}
}
class JavaScript {
js: any;
constructor(js: any) {
this.js = js;
}
helloJavaScript() {
console.log('Hello JavaScript')
}
}
function getLanguage(type: Type) {
let lang = type === Type.Strong ? new Java('java') : new JavaScript('js');
// in
if('java' in lang) {
lang.helloJava()
} else {
lang.helloJavaScript()
}
return lang;
}
getLanguage(Type.Strong); // Hello Java
function getLanguage(x: string | number) {
// typeof:此处只是提供一种创建类型保护区块的方法,并不解决此例中的问题
if(typeof x === 'string') {
console.log(x.length)
} else {
console.log(x.toFixed(2));
}
}
enum Type { Strong, Weak }
class Java {
helloJava() {
console.log('Hello Java')
}
}
class JavaScript {
helloJavaScript() {
console.log('Hello JavaScript')
}
}
// 注意类型保护的返回值,是一个“类型谓词”
function isJava(lang: Java | JavaScript): lang is Java {
return (lang as Java).helloJava !== undefined
}
function getLanguage(type: Type) {
let lang = type === Type.Strong ? new Java() : new JavaScript();
// 类型保护函数
if(isJava(lang)) {
lang.helloJava()
} else {
lang.helloJavaScript()
}
return lang;
}
getLanguage(Type.Strong); // Hello Java
Typescript 实战 --- (7)类型兼容性的更多相关文章
- 转载:《TypeScript 中文入门教程》 13、类型兼容性
版权 文章转载自:https://github.com/zhongsp 建议您直接跳转到上面的网址查看最新版本. 介绍 TypeScript里的类型兼容性基于结构子类型的. 结构类型是只一种只使用其成 ...
- typescript枚举,类型推论,类型兼容性,高级类型,Symbols(学习笔记非干货)
枚举部分 Enumeration part 使用枚举我们可以定义一些有名字的数字常量. 枚举通过 enum关键字来定义. Using enumerations, we can define some ...
- TypeScript 类型推导及类型兼容性
类型推导就是在没有明确指出类型的地方,TypeScript编译器会自己去推测出当前变量的类型. 例如下面的例子: let a = 1; 我们并没有明确指明a的类型,所以编译器通过结果反向推断变量a的类 ...
- TypeScript完全解读(26课时)_11.TypeScript完全解读-类型推论和兼容性
11.TypeScript完全解读-类型推论和兼容性 在一些时候省略指令,ts会帮我们推断出省略的类型的地方适合的类型,通过学习ts的类型推论了解ts的推论规则 类型兼容性就是为了适应js灵活的特点, ...
- TypeScript Type Compatibility(类型兼容)
TypeScript中的类型兼容是基于结构归类的.在普通分类的相比之下,结构归类是一种纯粹用于将其成员的类型进行关联的方法.思考下面的代码: interface Named { name: strin ...
- TypeScript Type Innference(类型推断)
在这一节,我们将介绍TypeScript中的类型推断.我们将会讨论类型推断需要在何处用到以及如何推断. 基础 在TypeScript中,在几个没有明确指定类型注释的地方将会使用类型推断来提供类型信息. ...
- TypeScript 之 基础类型、高级类型
基础类型:https://m.runoob.com/manual/gitbook/TypeScript/_book/doc/handbook/Basic%20Types.html 高级类型:https ...
- 聊聊 TypeScript 中的类型保护
聊聊 TypeScript 中的类型保护 在 TypeScript 中使用联合类型时,往往会碰到这种尴尬的情况: interface Bird { // 独有方法 fly(); // 共有方法 lay ...
- TypeScript躬行记(5)——类型兼容性
TypeScript是一种基于结构类型的语言,可根据其成员来描述类型.以结构相同的Person接口和Programmer类为例,如下所示. interface Person { name: strin ...
随机推荐
- 140种Python标准库、第三方库和外部工具
导读:Python数据工具箱涵盖从数据源到数据可视化的完整流程中涉及到的常用库.函数和外部工具.其中既有Python内置函数和标准库,又有第三方库和工具. 这些库可用于文件读写.网络抓取和解析.数据连 ...
- web.xml和@WebServlet
web.xml <servlet> <servlet-name>DZDYServlet</servlet-name> <servlet-class>包名 ...
- zoj 4124 "Median" (思维?假的图论?)
传送门 来源:2019 年“浪潮杯”第十届山东省 ACM 省赛 题意: 对于一个包含n个数的(n为奇数)序列val[ ],排序后的 val[ (n+1) / 2 ] 定义为 median: 有 n 个 ...
- BAT 脚本判断当前系统是 x86 还是 x64 系统
本文告诉大家在写 BAT 脚本的时候,如何判断当前的系统是 32 位系统的还是 64 位系统 通过注册表进行判断方法 @echo OFF reg Query "HKLM\Hardware\D ...
- Jasypt加密SpringBoot配置文件
如果 SpringBoot 的 properties 文件中含有用户名密码等敏感信息,为了安全起见需要对明文密码加密.Jasypt 是用来加密的 jar 包. 1.引入 Jasypt 在 pom.xm ...
- C++动态数组中的C6385, C6386警告
警告 C6385 从“m”中读取的数据无效: 可读大小为“col*sizeof(int)”个字节,但可能读取了“8”个字节. 警告 C6386 写入到“m”时缓冲区溢出: 可写大小为“col*size ...
- CFEducational Codeforces Round 66题解报告
CFEducational Codeforces Round 66题解报告 感觉丧失了唯一一次能在CF上超过wqy的机会QAQ A 不管 B 不能直接累计乘法打\(tag\),要直接跳 C 考虑二分第 ...
- css隐藏滚动条、移动端滚动卡顿的解决
1.如果想保持容器能够滚动,同时不想看到丑陋的滚动条,chrome.firefox和移动端上不考虑兼容性直接 element::-webkit-scrollbar{ display:none } 2. ...
- 西游记之孙悟空三打白骨精(IMAX)
短评:看了20分钟就有玩手机的冲动.剧情还差点意思,不能达到吸引人目不转睛的程度
- 第二阶段:1.流程图:11.PPT绘制页面流程图
产品经理主要绘制两个图:1.业务流程图(谁在什么条件下完成什么任务)2.页面流程图(具体到产品呈现的功能设计等等细节方面) 选择插入 选择流程图中的形状 设置两个矩形 同时添加不同的背景色 添加文本框 ...