Ts学习断言-守卫
断言
类型断言:
你可以通过类型断言的方式告诉编译器,相信我,我知道自己在干吗,类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你已经进行了必须的检查。
类型断言有两种形式,一种是尖括号,一种是as,jsx中可以用as写法。
let someValue: any = "this is a string";
//尖括号写法
let strLength: number = (<string>someValue).length;
//as写法
let strLength: number = (someValue as string).length;
//使用类型断言错误时,无法转换类型,但是可以保护代码不崩溃
let a: any = 8; //变量a被类型推断为number
console.log(a as string); // 输出8 :number类型
console.log((a as string).length); //输出undifined
非空断言
- 「x! 将从 x 值域中排除 null 和 undefined」
function myFunc(maybeNumber: number | undefined | null) {
// Type 'string | null | undefined' is not assignable to type 'string'.
// Type 'undefined' is not assignable to type 'string'.
const onlyNumber: number = maybeNumber; // Error
const ignoreUndefinedAndNull: number = maybeString!; // Ok
}
小结:上面不做操作,maybeNumber的类型存在undefined和null,会出现报错,但是加上非空断言以后,就只剩number了。
- 调用函数时忽略undefined
type NumGenerator = () => number;
function myFunc(numGenerator: NumGenerator | undefined) {
const num1 = numGenerator(); // Error
const num2 = numGenerator!(); //OK
}
小结:非空断言是你和编译器的互相欺骗你骗他你知道函数不靠谱的返回结果,他骗你不靠谱的代码之后会运行正常。
确认赋值断言
- 告诉ts该属性会被明确的赋值。
//不使用时,没赋值前使用会报错
let x: number;
initialize();
// Variable 'x' is used before being assigned.(2454)
console.log(2 * x); // Error
function initialize() {
x = 10;
}
//使用时,告诉ts这个值会被赋值,在编译阶段,因为预编译的原因可以正常
let x!: number;
initialize();
console.log(2 * x); // Ok
function initialize() {
x = 10;
}
类型守卫:
类型守卫是可以执行运行时检查的一种表达式,用于确保该类型在一定范围内,
- in关键字
interface Admin {
name: number;
privileges: string[];
}
interface Employee {
name: number;
startDate: Date;
}
type UnknownEmployee = Employee | Admin;
function printEmployeeInformation(emp: UnknownEmployee) {
console.log("Name: " + emp.name);
if ("privileges" in emp) {
console.log("Privileges: " + emp.privileges);
}
if ("startDate" in emp) {
console.log("Start Date: " + emp.startDate);
}
}
小结:in关键字就是给你一个选择,你可以选择有限类型中定义的类型,上例中,如果你的值在admin中,就从admin中取,如果你的值在employee中,就从employee中取
- typeof关键字
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
小结:typeof保护只支持两种模式typeof x==="dataType",dataType必须为"number","string","boolean",或者symbol。ts不会阻止其他的比较,但是不会把那些表达式识别为类型保护。
- instanceof 关键字,我的理解就是类型细化
interface Padder {
getPaddingString(): string
}
class SpaceRepeatingPadder implements Padder {
constructor(private numSpaces: number) { }
getPaddingString() {
return Array(this.numSpaces + 1).join(" ");
}
}
class StringPadder implements Padder {
constructor(private value: string) { }
getPaddingString() {
return this.value;
}
}
function getRandomPadder() {
return Math.random() < 0.5 ?
new SpaceRepeatingPadder(4) :
new StringPadder(" ");
}
// 类型为SpaceRepeatingPadder | StringPadder
let padder: Padder = getRandomPadder();
if (padder instanceof SpaceRepeatingPadder) {
padder; // 类型细化为'SpaceRepeatingPadder'
}
if (padder instanceof StringPadder) {
padder; // 类型细化为'StringPadder'
}
小结:本来padder拥有几个类型选择,instanceof将他选择范围细分开来
- 自定义类型保护的类型谓词
function isNumber(x: any): x is number {
return typeof x === "number";
}
function isString(x: any): x is string {
return typeof x === "string";
}