打字稿无法检查函数返回类型上的嵌套对象

时间:2021-04-22 09:23:30

标签: typescript typechecking

如果返回类型是嵌套对象,Typescript 将无法检查返回类型。考虑下面的代码,即使函数 A 中的结果变量与输出类型明显不匹配,Typescript 也不会发出错误。

interface Input {
  a: string;
  b: number;
}

interface Output {
  c: Omit<Input, 'a'>;
  d: string;
}

function A(input: Input): Output {
  const result = { c: {a: 'aaa', b: 3}, d: 'okay' };

  // Expect to have an error since the result is not matched to Output
  // but there's not errors
  return result;
}

function B(input: Input): Output {
  const result = "{ c: {a: 'aaa', b: 3}, d: 'okay' }";

  // Work as expected
  return result;
}

// But access a property will give us error. 
const test = A({ a: 'a', b: 3 });
test.c.a

Playground here

知道为什么会这样吗?

如果我们明确告诉 Typescript const result: Output = ...,它会给我们错误。但我不确定这是否是一个好习惯。还有其他方法可以让它按预期工作吗?

1 个答案:

答案 0 :(得分:1)

<块引用>

知道为什么会这样吗?

如果我们明确告诉 Typescript const result: Output = ...,它会给我们错误....

TypeScript 对对象文字应用比对其他表达式(包括变量引用)更严格的类型检查。在这种情况下,当您为 result 显式提供类型时,“更严格”的部分是 excess property check。¹ 这是一个实用检查,因为通常这是程序员错误,但在一般情况下 case 多余的属性没问题(因为对象的形状仍然匹配目标类型,它只是一个子类型,因为它有更多的属性)。

如果直接返回也会报错:

function A(input: Input): Output {
    return { c: {a: 'aaa', b: 3}, d: 'okay' };
}

虽然(主观上)我通常更喜欢你的原始代码,因为它更容易调试。

这在很大程度上是风格问题,但我会尽可能通过将其作为一般做法来解决问题:

function A(input: Input) {
//                      ^−−−− No return type annotation
    const result: Output = { c: {a: 'aaa', b: 3}, d: 'okay' };
//                ^−−−−−−−−−− Explicit type

    return result; // <−−−−−− TypeScript infers return type
}

请注意,函数的返回类型仍然是 Output,只是 TypeScript 是从 return 推断出来的,而不是我们在两个地方明确指定它。

Playground link


¹ 当我在 2021 年 4 月写这篇文章时,TypeScript 文档正在经历一次重大重写,链接的页面被列为“已弃用”,并添加了“新页面”的新内容,但新页面还没有描述多余的财产检查。希望这能尽快解决。