类型推断

类型推断

通过定义推断

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;
}
上一页