【问题标题】:Is there a TypeScript compiler option to force type checks on object properties?是否有 TypeScript 编译器选项来强制对对象属性进行类型检查?
【发布时间】:2018-01-20 14:23:37
【问题描述】:

为了编写更健壮的代码,我正在考虑将 TypeScript 用于我的基于 Web 的项目。到目前为止,我对这门语言的经验相对较少,但我遇到了一个我很难搜索的问题。

考虑下面的 TypeScript 代码:

public static getResponseCode(resObj: object): number {
    let c: number = resObj["c"]
    return c;
}

有没有一种方法可以强制 TypeScript 编译器将我拉到这里并告诉我 resObj["c"] 可能不是数字,我需要先检查它是否是数字?例如。我可以强制 TypeScript 让我像这样(或类似的东西)重写代码吗?:

public static getResponseCode(resObj: object): number {
    if (typeof resObj["c"] !== "number") { return APIResponseCode.UnknownFailure; }

    let c: number = resObj["c"]
    return c;
}

我希望我得到的结果仅仅是因为resObj["c"] 的类型是any。我可以在这里做什么? TypeScript 中是否有通用模式?

【问题讨论】:

  • 使用 resObj.c 而不是 resObj["c"] 对属性 c 进行类型检查。
  • 类型 object 没有属性 c。 @torazaburo

标签: typescript typing


【解决方案1】:

您可以打开noImplicitAny 编译器选项。然后,编译器会在任何时候隐式地抱怨任何事情。

我们在tsconfig.json 中设置了 noImplictAny。

{
    "compilerOptions": {
        "noImplicitAny": true
    }
}

或者我们在命令行中这样设置tsc --noImplicitAny

这会迫使你做某事。

例如,您可以显式使用 any。

public static getResponseCode(resObj: object): number {
    const resAny = resObj as any;
    if (resAny.c && typeof resAny.c !== "number") {
        return APIResponseCode.UnknownFailure;
    }

    const c: number = resAny.c;
    return c;
}

或者您可以使用带有a union type and a type guard 的接口。

interface ResObj {
    c: boolean | string | number | object;
}

public static getResponseCode2(resObj: ResObj): number {

    if (typeof resObj.c !== "number") {
        return APIResponseCode.UnknownFailure;
    }

    const c: number = resObj.c;
    return c;
}

【讨论】:

  • 这似乎正是我想要的。非常感谢。您能否建议我是否应该使用object 类型来传递对JSON.parse 的调用结果?还是我应该使用any
  • 我正在使用 TypeScript 生成客户端 Javascript。我的 API 的所有请求/响应都通过 jQuery AJAX 作为传统的 javascript JSON 对象发送。我要问的是,在传递这些请求和响应对象时使用object 类型或使用any 类型更有意义吗?我无法为所有可能的请求和响应创建接口,因为它们差异很大。你有什么建议?
  • @LukePark JSON.parse() 返回一个object,所以我会使用object 而不是any,因为any 也可以是一个原语,例如boolean,其中JSON.parse()永远不会回来。
  • 当我在构造一个请求对象的时候呢?如果我执行reqObj.t = "asd"; 之类的操作,则会得到“类型对象上不存在属性't'...”等。
  • 这取决于您是否希望编译器帮助您。如果你打算使用any,那么编译器将停止帮助你,因为any 会让你退出静态类型检查。因此,anyobject(或其他类型)之间的选择是一种权衡。我们需要在使用动态语言开发的便利性和使用类型化语言开发的安全性之间做出选择。
【解决方案2】:

TypeScript 不进行运行时类型检查。根据您要执行的操作,您有几个选择。首先是为resObj定义一个接口:

interface ResObj { c: number; }

现在

public static getResponseCode(resObj: ResObj): number {
  let c: number = resObj.c;
  return c;
}

如果您传递 getResponseCodeResObj 不匹配的内容(带有不是数字的 c 属性),您的代码现在将无法编译。

如果您希望c 可能是一个数字,或者可能是一个字符串,该怎么办?在这种情况下,请使用联合类型:

interface ResObj { c: number | string; }

您上面的getResponseCode 的原始版本现在将无法编译。 TypeScript 会抱怨它不知道如何将string | number 转换为number

如果您按照您的建议编写代码:

public static getResponseCode(resObj: ResObj): number {
  if (typeof resObj.c !== "number") { return APIResponseCode.UnknownFailure; }

  let c: number = resObj.c;
  return c;
}

TypeScript 会很高兴,因为它的流分析检测到 typeof 检查并知道当它到达 return 语句时,c 只能是一个数字。

对于更复杂的情况,您可以使用所谓的类型保护,它明确告诉 TypeScript 特定函数保证其参数的特定类型:

function isNumber(c: string | number): c is number {
  return typeof c === 'number';
}

现在你可以写了

public static getResponseCode(resObj: ResObj): number {
  if (!isNumber(resObj.c)) { return APIResponseCode.UnknownFailure; }

  let c: number = resObj.c;
  return c;
}

【讨论】:

  • 感谢您的回答。我想我现在只能坚持使用typeof 检查,因为我传递给getResponseCode 的对象是在运行时收到的,正如你所说,没有运行时类型检查发生。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2011-06-15
  • 2019-09-30
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-10
  • 1970-01-01
相关资源
最近更新 更多