类型检查机制:TypeScript编译器在做类型检查时,所秉承的一些原则,以及表现出的一些行为。
作用:辅助开发,提高开发效率。
类型推断
:指不需要指定变量的类型(函数的返回值类型),TypeScript可以根据某些规则自行的推断出一个类型
1.基础类型推断
2.最佳通用类型推断
3.上下文类型推断
- 前两者都是从右往左的推断,根据值去推断, 例如 let a = 1 // a 被推断的类型是 number
let a = 1- 最佳通用类型推断 例如 let b = [1, 'a'] // b 的最佳通用类型 (string | number)[]
let b = [1, 'a']
let c = (x = 1) => x + '2' // function(x: number): string- 根据上下类型推断 例如 window.onkeydown = (event) => {} // 推断 event 为 KeyboardEvent
window.onkeydown = (event) => {
console.log(event)
}
关于类型断言
interface Foo {
bar: number
}
let foo = {} as Foo
foo.bar = 1
/**
* 以上使用`as`的方式,不会提示是否缺失定义`bar`属性,
* 最好的方式是使用下面代码,在定义时就指明类型
*
* Property 'bar' is missing in type '{}' but required in type 'Foo'.
*/
let foo02 : Foo = {
bar: 1
}类型兼容性:(当一个类型Y可以被赋值给另一个类型X时,可以说类型X兼容类型Y) =》X(目标类型)=Y(源类型)
- 口诀:
结构之间兼容:成员少的兼容成员多的
函数之间兼容:参数多的兼容参数少的
- 接口兼容性:成员少 兼容 成员多的(前提:源类型具备目标类型的必要属性 则可以向其兼容)
interface X {
a: number;
b: number;
}
interface Y {
a: number;
b: number;
c: number;
}
let xx: X = { a: 1, b: 2}
let yy: Y = { a: 1, b: 2, c: 3 }
// yy = xx // Property 'c' is missing in type 'X' but required in type 'Y'
xx = yy // Ok- 函数兼容性
type Handler = (a: number, b: number) => void
function hof(handler: Handler) {
return handler
}
// 1.参数个数
let handler1 = (a: number) => {}
hof(handler1)
let handler2 = (a: number, b: number, c: number) => {}
// hof(handler2) // 源函数参数3个 而目标函数参数2个 所以不能达到兼容
// 可选参数和剩余参数
let a1 = (p1: number, p2: number) => {}
let b1 = (p1?: number, p2?: number) => {}
let c1 = (...arg: number[]) => {}
// 固定参数可兼容可选/剩余
// a1 = b1
// a1 = c1
// 可选参数不可兼容固定/剩余 改变"strictFunctionTypes"为 false可进行兼容
// b1 = a1
// b1 = c1
// 剩余参数可兼容可选/固定
c1 = a1
c1 = b1
// 2.参数类型
// 简单类型
let handler3 = (a: string) => {}
// hof(handler3) // 类型不兼容
// 复杂类型(对象)
interface Point3D {
x: number;
y: number;
z: number;
}
interface Point2D {
x: number;
y: number;
}
let p3d = (point: Point3D) => {};
let p2d = (point: Point2D) => {};
p3d = p2d
// p2d = p3d // 成员多 兼容 成员多少的 改变"strictFunctionTypes"为 false可进行兼容
/* 3.返回值类型 Ts要求函数定理类型与返回值类型相同或为其子类型
* 少的可以兼容多的
*/
let f1 = () => ({ name: 'jessiex' })
let f2 = () => ({ name: 'jessiex', age: '2' })
f1 = f2
// f2 = f1 // 无法兼容- 枚举类型
enum Fruit { Apple, Banana }
enum Color { Red, Yellow }
let fruit: Fruit.Apple = 3
let no: number = Fruit.Apple // 枚举与number之间是相互兼容的
// let color: Color.Red = Fruit.Apple // 枚举之间相互不兼容- 类类型
// 比较两个类是否兼容时,静态成员和构造函数是不参与比较的
class A {
constructor(p: number,q:number) {}
id: number = 1
private name: string = ''
}
class B {
static s =1
constructor(p: number) {}
id: number = 2
}
let aa = new A(1,2)
// let bb = new B(1)
// aa = bb OK
// bb = aa OK
// 在拥有私有成员时,只有父类和子类之间相互兼容
class C extends A {}
let cc = new C(1,2)
cc = aa // (aa=bb)Fail
aa = cc // (bb=bb)Fail类型保护
指TS能够在特定的区块中保证变量属于某种确定的类型。可以再次区块中放心的引用此类型的属性,或者调用此类型的方法
enum Type { Strong, Weak }
class Java {
helloJava() {
console.log('hello,Java')
}
java: any;
}
class JavaScript {
helloJavaScript() {
console.log('hello,JavaScript')
}
js: any;
}
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.Strong ? new Java() : new JavaScript();
// 1.instanceof 通过判断一个实例是否属于某个类
if (lang instanceof Java) {
lang.helloJava()
} else {
lang.helloJavaScript()
}
// 通过判断一个属性是否属于某个对象
if ('java' in lang) {
lang.helloJava()
} else {
lang.helloJavaScript()
}
// 3.typeof 通过判断一个变量的类型(借助变量x示范)
if (typeof x === 'string') {
console.log(x.length)
} else {
x.toFixed(2)
}
// 4.类型保护函数:某些判断可能不是一条语句能够搞定的,需要更多复杂的逻辑,适合封装到一个函数内
if (isJava(lang)) {
lang.helloJava()
} else {
lang.helloJavaScript()
}
return lang;
}
















