类型思维
- 思维方式决定了编程习惯
- 编程习惯奠定了工程质量
- 工程质量划定了能力边界
强类型与弱类型
对于强类型语言没有一个准确的定义,其中一种定义是:
在强类型语言中,当一个对象从调用函数传递到被调用函数时,其类型必须与被调用函数中上面的类型兼容
A() {B(x)}B(y) {// y 可以被赋值x,程序运行良好}
后者对其的定义更加准确
强类型语言:不允许改变变量的数据类型,除非进行强制类型转换
什么是弱类型语言:
变量可以被赋值不同的数据类型
静态类型语言与动态类型语言
- 静态类型语言:在编译阶段确定所有变量的类型
- 动态类型语言:在执行阶段确定所有变量的类型 | 静态类型语言 | 动态类型语言 | | —- | —- | | 对类型极度严格 | 对类型非常宽松 | | 立即发现错误 | Bug可能隐藏数月甚至数年 | | 运行时性能好 | 运行时性能差 | | 自文档化 | 可读性差 |
动态类型语言的支持者认为:
- 性能时可以改善的(V8引擎),而语言的灵活性更加重要
- 隐藏的错误可以通过单元测试发现
- 文档可以通过工具生成
第一个 TypeScript 程序
interface Persen {name: string;age?: number;}let zhangsan: Persen = {name: 'zhangsna',}const add = (s: string, n: number): number => {return Number(s) + n;}class Animal {name: stringconstructor(name: string) {this.name = name}run() {return `${this.name} is running`}}class Dog extends Animal {bark() {return `${this.name} is braking`}}class Cat extends Animal {static categories = ['mammal']constructor(name: string) {super(name)console.log(this.name)}run() {return `Meow,${super.run()}`}}// const dog = new Dog('xiaoming');// console.log(dog.run());// console.log(dog.bark());const mao = new Cat('mao')console.log(mao.run())console.log(Cat.categories)interface Radio {switchRadio(trigger: boolean): void}interface Battery {checkBatteryStatus(): void}interface RadioWithBattery extends Radio {checkBatteryStatus(): void}class Car implements Radio {switchRadio(trigger: boolean): void {}}class Cellphone implements RadioWithBattery {switchRadio(trigger: boolean): void {}checkBatteryStatus(): void {}}enum Diretion {Up = 10,Down,Left,Right}console.log(Diretion.Up)console.log(Diretion[0])interface IWithLength {length: number}function echo<T extends IWithLength>(arg: T): T {console.log(arg.length)return arg}const result = echo('str')interface IName {name: string}type IPerson = IName & { age: number }let person: IPerson = { name: '123', age: 12 }
接口
函数
类
继承和成员修饰符
抽象类与多态
类与接口的关系
泛型
泛型函数与泛型接口
泛型类与泛型约束
类型检查机制
类型判断
类型兼容
结构之间兼容:成员少的兼容成员多的
函数之间兼容:参数多的兼容成员少的
接口类型兼容
函数类型兼容
- 固定参数不兼容固定参数和剩余参数
- 可选参数不兼容固定参数和剩余参数
返回值类型一致或者兼容类型
let a = (p1: number, p2: number) => {};let b = (p1?: number, p2?: number) => {};let c = (...arg: number[]) => {};a = b;a = c;b = c; //errorb = a; //error
枚举类型兼容
枚举类型与数值类型是完全兼容的
- 枚举类型之间完全不兼容
类兼容性
具有相同的实例成员,静态成员和构造函数不参与兼容性比较泛型兼容性
只有泛型接口中类型T使用的时才会影响类型的兼容性类型保护
typescript能够在特定的区块中保证变量属于某种确定的类型。可以在此区块中放心引用此类型的属性,或者调用此类型的方法。
// instanceofif(lang instanceof Java) {lang.helloJava()} else {lang.helloJavaScript()}// inif('java' in lang) {lang.helloJava()} else {lang.helloJavaScript()}// typeof 判断基本类型if(typeof x === 'string') {x.length} else {x.toFixed(2)}// 类型保护函数function isJava(lang:Java | JavaScript): lang is Java {return (lang as Java).helloJava !== undefined}function getLanguage(type:Type,x:string|number) {let lang =type=Type.String?new Java():new JavaScript()if(isJava(lang)) {lang.helloJava()} else {lang.helloJavaScript()}}
高级类型
交叉类型与联合类型
索引类型
# key 的类型是obj对象属性的联合类型let key: keyof obj;
注意点
一般情况下优先使用类型注解的方式,必须谨慎使用类型断言,如果你没有添加对应的属性ts不会发出警告
interface Foo {bar: number;bas: string;}const foo = {} as Foo;
当 S 类型是 T 类型的子集,或者 T 类型是 S 类型的子集时,S 能被成功断言成 T。这是为了在进行类型断言时提供额外的安全性,完全毫无根据的断言是危险的,如果你想这么做,你可以使用 any。
