类型推断
类型推断
通过定义推断
let foo = 123; // foo 是 'number'
let bar = "hello"; // bar 是 'string'
foo = bar; // Error: 不能将 'string' 赋值给 `number`
// 返回类型能被 return 语句推断,如下所示,推断函数返回为一个数字:
function add(a: number, b: number) {
return a + b;
}
函数参数类型/返回值也能通过赋值来推断。如下所示,foo 的类型是 Adder,他能让 foo 的参数 a、b 是 number 类型。
type Adder = (a: number, b: number) => number;
let foo: Adder = (a, b) => a + b;
这个事实可以用下面的代码来证明,TypeScript 会发出正如你期望发出的错误警告:
type Adder = (a: number, b: number) => number;
let foo: Adder = (a, b) => {
a = 'hello'; // Error:不能把 'string' 类型赋值给 'number' 类型
return a + b;
};
这是一个从左向右流动类型的示例。如果你创建一个函数,并且函数参数为一个回调函数,相同的赋值规则也适用于它。从 argument 至 parameter 只是变量赋值的另一种形式。
type Adder = (a: number, b: number) => number;
function iTakeAnAdder(adder: Adder) {
return adder(1, 2);
}
iTakeAnAdder((a, b) => {
a = "hello"; // Error: 不能把 'string' 类型赋值给 'number' 类型
return a + b;
});
结构化与解构推断
这些简单的规则也适用于结构化的存在(对象字面量),例如在下面这种情况下 foo
的类型被推断为 { a: number, b: number }
:
const foo = {
a: 123,
b: 456
};
foo.a = "hello"; // Error:不能把 'string' 类型赋值给 'number' 类型
数组也一样:
const bar = [1, 2, 3];
bar[0] = "hello"; // Error:不能把 'string' 类型赋值给 'number' 类型
这些也适用于解构中:
const foo = {
a: 123,
b: 456
};
let { a } = foo;
a = "hello"; // Error:不能把 'string' 类型赋值给 'number' 类型
数组中:
const bar = [1, 2];
let [a, b] = bar;
a = "hello"; // Error:不能把 'string' 类型赋值给 'number' 类型
如果函数参数能够被推断出来,那么解构亦是如此。在如下例子中,函数参数能够被解构为 a/b
成员:
type Adder = (number: { a: number; b: number }) => number;
function iTakeAnAdder(adder: Adder) {
return adder({ a: 1, b: 2 });
}
iTakeAnAdder(({ a, b }) => {
// a, b 的类型能被推断出来
a = "hello"; // Error:不能把 'string' 类型赋值给 'number' 类型
return a + b;
});
类型保护
我们可以使用 typeof
, instanceof
, in
来实现手动类型推导,typeof
可以获取变量的数据类型:
function foo(x: string | number) {
if (typeof x === "string") {
return x; // string
}
return x; // number
}
instanceof
可以用于判断某个对象是否是某个类的实例:
function f1(x: B | C | D) {
if (x instanceof B) {
x; // B
} else if (x instanceof C) {
x; // C
} else {
x; // D
}
}
in
用于更方便地进行 object
类型的推导:
interface A {
a: number;
}
interface B {
b: string;
}
function foo(x: A | B) {
if ("a" in x) {
return x.a;
}
return x.b;
}