TypeScript 中的运行时类型安全

Sac*_*har 6 typescript angular

我试图更好地理解 Typescript 中的类型安全性,并遇到了这个场景,我有这个函数:

function test(x: number){
    console.log(typeof x);
}
Run Code Online (Sandbox Code Playgroud)

如果我这样调用这个方法 - test('1')它会抛出编译时错误,但如果我将其更改为这样,它就可以正常工作:

let y: any = '1';
test(y);
//works fine
//Outputs "string"
Run Code Online (Sandbox Code Playgroud)

据我了解,将“x”声明为数字仅在编译时有效,并且 Typescript 仅强制编译时类型安全而不是运行时。所以,我想知道我是否理解正确或遗漏了任何内容,以及确保运行时类型安全的不同方法是什么?

Mac*_*ora 8

TypeScript 是两种合并的语言:

  1. 类型级别语言
  2. 价值层面的语言

第一个是所有类型注释都可见的,它是纯 JavaScript 中不存在的语法。每个类型注释和保留字type, interface, enum, as, in都是类型级别语言的一部分。TS 在编译过程中首先要做的是检查类型级语言的语法和语法的正确性以及值级语言的注释的正确性。

第二个是值级语言,它是完全正确的JS语法。它还具有 ECMAScript 提案第 3 阶段的大部分功能。

第一部分被完全删除(例外是 Enum,它在运行时中有表示),第二部分保留在运行时中。

回到关于安全的问题,是的,TypeScript 在编写代码时确保安全。您定义合约,编写合约的转换,TS 会检查与合约注释相关的代码的正确性。它消除了一大堆错误,例如拼写错误,或使用 null/未定义的对象方法和属性,它还在程序流程中提供了数据的可见定义。

但是,它并不能保证运行时的安全。所有类型注释都只是假设,如果我们定义API有这样那样的端点响应结构,那么TS将保证代码将遵循这个结构,但如果在运行时,结构会有所不同,程序自然会失败,因为合同不等于数据。

回到你的例子

function test(x: number){
    console.log(typeof x);
}
Run Code Online (Sandbox Code Playgroud)

将函数定义test为以参数为参数的函数number,您所说的没有什么不同,然后number将传递给该函数。所以上面的实现实际上是一个常量,因为它typeof x总是返回number,因为这正是注释所说的。

// below is equal to your implementation, as number has one specific type
// caution is equal for TS, not for the runtime!
function test() {
  return console.log('number')
}
Run Code Online (Sandbox Code Playgroud)

如果函数在输入方面是多态的,那么输入应该如此注释。有时您不知道可以获得什么输入,那么您可以实现结构检查。其正确的名称是类型防护。考虑下面的例子

function test(x: unknown) {
  if (typeof x === 'number') {
    return x * 2; // return number
  }
  if (typeof x === 'string') {
    return x + '- I am string'; // return number
  }

  if (typeof x === 'object') {
    return x; // return object;
  }

  return null; // for others return null
}
Run Code Online (Sandbox Code Playgroud)

现在函数test已推断输出为 union string | number | object | null。通过使用控制流和条件,TS 能够理解函数返回的内容。

每次您的代码处理某些多态类型时,您都可以使用类型保护来准确指定您正在使用的类型。检查是通过结构体完成的(因为运行时只存在结构体,类型仅在代码编写期间注释结构体),因此您可以检查typeof,instanceof或 对象是否具有特定的键或值。

要记住的非常重要的事情 -类型是某些现有运行时结构的标签。标签/类型在运行时不存在,但结构存在。这就是 TS 能够理解类型保护的原因,因为每种类型都引用某种结构。


Kew*_*sse 5

运行时类型安全与 TypeScript 无关。TypeScript 团队非常清楚该语言的目标,您可以在wiki 的“非目标”部分阅读以下行:

提供额外的运行时功能或库。

如果您正在寻找运行时类型安全性,则必须寻找其他地方。

最重要的是,您可以通过声明变量的类型来主动禁用您可能希望对变量进行的类型检查any。您可以在手册上阅读有关该行为的信息

TS 中的运行时类型检查策略与 JS 中的相同,因为在运行时,不再有任何 TS,都是 JavaScript。