类型检查机制:TypeScript编译器在做类型检查时,所秉承的一些原则,以及表现出的一些行为。
作用:辅助开发,提高开发效率。
类型检查机制通常有:
- 类型推断
- 类型兼容性
- 类型保护
类型推断
不需要指定变量的类型(函数的返回值类型),TypeScript可以根据某些规则自动地为其推断出一个类型。
类型推断通常分为:
- 基础类型推断
- 最佳通用类型推断
- 上下文类型推断
/**
* 基础类型推断
*/
let a = 1
let 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 = 1
let foo: Foo = {
bar: 1
}
类型兼容性
当一个类型Y可以被赋值给另一个类型X时,我们就可以说类型X兼容类型Y
X兼容Y:X(目标类型) = Y(源类型)
口诀:
结构之间兼容: 成员少的兼容成员多的
函数之间兼容: 参数多的兼容参数少的
/**
* 基础类型推断
*/
let a = 1
let 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 = 1
let 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) => void
function 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 = b1
a1 = c1
b1 = c1
b1 = a1
c1 = a1
c1 = 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 = h
function 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 = 3
let 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 = 1
constructor(p: number) {}
id: number = 2
}
let aa = new J(1,2);
let bb = new K(1);
aa = bb
bb = aa
class L extends J {}
let cc = new L(1, 2)
aa = cc
cc = 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)