类型思维
- 思维方式决定了编程习惯
- 编程习惯奠定了工程质量
- 工程质量划定了能力边界
强类型与弱类型
对于强类型语言没有一个准确的定义,其中一种定义是:
在强类型语言中,当一个对象从调用函数传递到被调用函数时,其类型必须与被调用函数中上面的类型兼容
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: string
constructor(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; //error
b = a; //error
枚举类型兼容
枚举类型与数值类型是完全兼容的
- 枚举类型之间完全不兼容
类兼容性
具有相同的实例成员,静态成员和构造函数不参与兼容性比较泛型兼容性
只有泛型接口中类型T使用的时才会影响类型的兼容性类型保护
typescript能够在特定的区块中保证变量属于某种确定的类型。可以在此区块中放心引用此类型的属性,或者调用此类型的方法。
// instanceof
if(lang instanceof Java) {
lang.helloJava()
} else {
lang.helloJavaScript()
}
// in
if('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。