TypeScript 类型断言&类型保护
程序员文章站
2022-07-12 15:41:29
...
目录
类型断言
含义
TypeScript 允许你覆盖它的推断,并且能以你任何你想要的方式分析它,这种机制被称为「类型断言」。
语法一:尖括号
let foo: any;
let bar = <string>foo; // 现在 bar 的类型是 'string'
语法二:as
let foo: any;
let bar = foo as string; // 现在 bar 的类型是 'string'
与类型转换的区别
它之所以不被称为「类型转换」,是因为转换通常意味着某种运行时的支持。
但是,类型断言纯粹是一个编译时语法,同时,它也是一种为编译器提供关于如何分析代码的方法。
类型保护
功能
类型保护允许你使用更小范围下的对象类型。
实现一:typeof
typeof x === “typename”
typeof x !== “typename”
这里的typename只能是 “undefined”, “number”, “string”, “boolean”, “bigint”, “symbol”, “object” 或 “function”。
function doSome(x: number | string) {
if (typeof x === 'string') {
// 在这个块中,TypeScript 知道 `x` 的类型必须是 `string`
console.log(x.substr(1)); // ok
}
x.substr(1); // Error: 无法保证 `x` 是 `string` 类型
}
实现二: instanceof
class Foo {
foo = 123;
common = '123';
}
class Bar {
bar = 123;
common = '123';
}
function doStuff(arg: Foo | Bar) {
if (arg instanceof Foo) {
console.log(arg.foo); // ok
console.log(arg.bar); // Error
}
if (arg instanceof Bar) {
console.log(arg.foo); // Error
console.log(arg.bar); // ok
}
}
doStuff(new Foo());
doStuff(new Bar());
TypeScript 甚至能够理解 else。当你使用 if 来缩小类型时,TypeScript 知道在其他块中的类型并不是 if 中的类型:
class Foo {
foo = 123;
}
class Bar {
bar = 123;
}
function doStuff(arg: Foo | Bar) {
if (arg instanceof Foo) {
console.log(arg.foo); // ok
console.log(arg.bar); // Error
} else {
// 这个块中,一定是 'Bar'
console.log(arg.foo); // Error
console.log(arg.bar); // ok
}
}
doStuff(new Foo());
doStuff(new Bar());
实现三: in
in
操作符可以安全的检查一个对象上是否存在一个属性,它通常也被作为类型保护使用:
interface A {
x: number;
}
interface B {
y: string;
}
function doStuff(q: A | B) {
if ('x' in q) {
// q: A
} else {
// q: B
}
}
实现四:字面量类型保护
当你在联合类型里使用字面量类型时,你可以检查它们是否有区别:
type Foo = {
kind: 'foo'; // 字面量类型
foo: number;
};
type Bar = {
kind: 'bar'; // 字面量类型
bar: number;
};
function doStuff(arg: Foo | Bar) {
if (arg.kind === 'foo') {
console.log(arg.foo); // ok
console.log(arg.bar); // Error
} else {
// 一定是 Bar
console.log(arg.foo); // Error
console.log(arg.bar); // ok
}
}
实现五:自定义的类型保护 & 类型谓词
JavaScript 并没有内置非常丰富的、运行时的自我检查机制。当你在使用普通的 JavaScript 对象时(使用结构类型,更有益处),你甚至无法访问 instanceof 和 typeof。在这种情景下,你可以创建用户自定义的类型保护函数,这仅仅是一个返回值为类似于someArgumentName is SomeType 的函数,如下:
// 仅仅是一个 interface
interface Foo {
foo: number;
common: string;
}
interface Bar {
bar: number;
common: string;
}
// 用户自己定义的类型保护!
function isFoo(arg: Foo | Bar): arg is Foo {
return (arg as Foo).foo !== undefined;
}
// 用户自己定义的类型保护使用用例:
function doStuff(arg: Foo | Bar) {
if (isFoo(arg)) {
console.log(arg.foo); // ok
console.log(arg.bar); // Error
} else {
console.log(arg.foo); // Error
console.log(arg.bar); // ok
}
}
doStuff({ foo: 123, common: '123' });
doStuff({ bar: 123, common: '123' });
注:is
是类型谓词;
通过 x is type
来指定 x 的类型。