类型检查机制:TypeScript编译器在做类型检查时,所秉承的一些原则,以及表现出的一些行为。
作用:辅助开发,提高开发效率。
类型检查机制通常有:
- 类型推断
- 类型兼容性
- 类型保护
类型推断
不需要指定变量的类型(函数的返回值类型),TypeScript可以根据某些规则自动地为其推断出一个类型。
类型推断通常分为:
- 基础类型推断
- 最佳通用类型推断
- 上下文类型推断
/*** 基础类型推断*/let a = 1let b = [1]// let c = (x = 1) => {}let d = (x = 1) => x + 1/*** 最佳通用类型推断:从多个类型推断类型,TS会推荐兼容所有类型的类型*/// slet e = [1, null]/*** 上下文类型推断:从左往右进行推断,上面是从右往左进行推断*/window.onkeydown = (event) => {// console.log(event.button)}/*** 类型断言 as* 使用类型断言可以增加代码的灵活性,但是不可滥用,要对上下文有充足的预判,否则会有安全隐患*/interface Foo {bar: number}// let foo = {} as Foo// foo.bar = 1let foo: Foo = {bar: 1}
类型兼容性
当一个类型Y可以被赋值给另一个类型X时,我们就可以说类型X兼容类型Y
X兼容Y:X(目标类型) = Y(源类型)
口诀:
结构之间兼容: 成员少的兼容成员多的
函数之间兼容: 参数多的兼容参数少的
/*** 基础类型推断*/let a = 1let b = [1]// let c = (x = 1) => {}let d = (x = 1) => x + 1/*** 最佳通用类型推断:从多个类型推断类型,TS会推荐兼容所有类型的类型*/// slet e = [1, null]/*** 上下文类型推断:从左往右进行推断,上面是从右往左进行推断*/// window.onkeydown = (event) => {// // console.log(event.button)// }/*** 类型断言 as* 使用类型断言可以增加代码的灵活性,但是不可滥用,要对上下文有充足的预判,否则会有安全隐患*/interface Foo {bar: number}// let foo = {} as Foo// foo.bar = 1let foo: Foo = {bar: 1}/*** 类型兼容* X兼容Y:X(目标类型) = Y(源类型)*/// 关闭strictNullChecks时,字符串类型可以赋值null,这时,我们就可以说字符型兼容null类型let s: string = 'a's = null// 接口兼容性// 成员少的兼容成员多的interface X {a: any;b: any;}interface Y {a: any;b: any;c: any;}let z: X = {a: 1, b: 2}let y: Y = {a: 1, b: 2, c: 3}x = y// y = x// 函数兼容性type Handler = (a: number, b: number) => voidfunction hof(handler: Handler) {return handler}// 1).参数个数:目标函数的参数个数要多于源函数的参数个数let handler1 = (a: number) => {}hof(handler1)let handler3 = (a: number, b: number, c: number) => {}// hof(handler3)// 可选参数和剩余参数// 关闭strictFunctionTypes,可以兼容let a1 = (p1: number, p2: number) => {}let b1 = (p1?: number, p2?: number) => {}let c1 = (...args: number[]) => {}a1 = b1a1 = c1b1 = c1b1 = a1c1 = a1c1 = b1// 2).参数类型let handler4 = (a: string) => {}// hof(handler4)interface Point3D {x: number;y: number;z: number;}interface Point2D {x: number;y: number;}let p3d = (point: Point3D) => {};let p2d = (point: Point2D) => {};p3d = p2d// 关闭strictFunctionTypes可兼容以下p2d = p3d// 这种函数参数之间相互赋值的情况,叫做函数参数的双向协变// 3).返回值类型let h = () => ({name: 'Alice'});let g = () => ({name: 'Alice', location: 'shanghai'});h = g// g = hfunction overload1(a: number, b: number): number;function overload1(a: string, b: string): string;function overload1(a: any, b: any): any {};// 枚举兼容性enum Fruit { Apple, Banana }enum Color { Red, Green }let fruit: Fruit.Apple = 3let no: number = Fruit.Apple// 枚举之间是完全不兼容的// let color: Color.Red = Fruit.Apple// 类兼容性// 如果类中含有私有成员,则这两种类就不兼容,只有父类和子类相互兼容class J {constructor(p: number, q: number) {}id: number = 1// private name: string = ''}class K {static s = 1constructor(p: number) {}id: number = 2}let aa = new J(1,2);let bb = new K(1);aa = bbbb = aaclass L extends J {}let cc = new L(1, 2)aa = cccc = aa// 泛型兼容性// 泛型接口中没有任何成员是可以相互兼容的interface Empty<T> {value: T}// let obj1: Empty<number> = {};// let obj2: Empty<string> = {};// obj1 = obj2// 泛型函数的定义相同,但是没有指定类型参数,他们之间也是项目兼容的let log3 = <T>(x: T): T => {console.log('x')return x}let log4 = <U>(y: U): U => {console.log('y')return y}log3 = log4
类型保护
TypeScript 能够在特定的区块中保证变量属于某种确定的类型。
可以在此区块中放心地引用此类型的属性,或者调用此类型的方法。
enum Type { Strong, Week }class Java {helloJava() {console.log('hello Java')}java: any}class JavaScript {helloJavaScript() {console.log('hello JavaScript')}javascript: 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()// if ((lang as Java).helloJava) {// (lang as Java).helloJava()// } else {// (lang as JavaScript).helloJavaScript()// }// 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)// }//if(isJava(lang)) {lang.helloJava()} else {lang.helloJavaScript()}return lang}getLanguage(Type.Strong)
