Each and every value in JavaScript has a set of behaviors you can observe from running different operations. That sounds abstract, but as a quick example, consider some operations we might run on a variable named message.
JavaScript中的每个值都有一组行为,可以在运行不同的操作时观察到。这听起来很抽象,有个简单的例子,考虑一下我们可能在名为message的变量上运行的一些操作。
// Accessing the property 'toLowerCase' on 'message' and then calling itmessage.toLowerCase();// Calling 'message'message();
If we break this down, the first runnable line of code accesses a property called toLowerCase and then calls it. The second one tries to call message directly.
如果我们将其分解,第一行可运行代码将访问一个名为toLowerCase的属性,然后调用它。第二个尝试直接调用message方法。
But assuming we don’t know the value of message - and that’s pretty common - we can’t reliably say what results we’ll get from trying to run any of this code. The behavior of each operation depends entirely on what value we had in the first place.
但是假设我们不知道message 的值——这是很正常的——我们不能确信的说我们会从这些尝试着运行的代码中得到什么结果。每个操作的行为完全取决于我们在初始化的时候有什么值。
- Is
messagecallable? message可调用?- Does it have a property called
toLowerCaseon it? - 它有一个属性叫
toLowerCase吗? - If it does, is
toLowerCaseeven callable? - 如果有,
toLowerCase是否还可以调用? - If both of these values are callable, what do they return?
- 如果这两个值都是可调用的,它们返回什么?
The answers to these questions are usually things we keep in our heads when we write JavaScript, and we have to hope we got all the details right.
当我们在编写JavaScript时,这些问题的答案通常都在我们的头脑中,我们必须希望我们得到了所有的细节。
Let’s say message was defined in the following way.
让我们假设message 是按照以下方式定义的。
const message = "Hello World!";
As you can probably guess, if we try to run message.toLowerCase(), we’ll get the same string only in lower-case.
正如你可能猜到的,如果我们尝试运行message.toLowerCase(),我们会得到相同的字符串,只是小写的。
What about that second line of code? If you’re familiar with JavaScript, you’ll know this fails with an exception:
那么第二行代码呢?如果你熟悉Javascript,你会知道这是一个失败异常:
TypeError: message is not a function
It’d be great if we could avoid mistakes like this.
如果我们能避免这样的错误就好了。
When we run our code, the way that our JavaScript runtime chooses what to do is by figuring out the type of the value - what sorts of behaviors and capabilities it has. That’s part of what that TypeError is alluding to - it’s saying that the string "Hello World" cannot be called as a function.
当我们运行代码时,JavaScript运行时选择怎么操作是通过计算值的类型——它具有什么样的行为和功能。这就是TypeError所暗示的部分内容——它说字符串“Hello World”不能作为函数调用。
For some values, such as the primitives string and number, we can identify their type at runtime using the typeof operator. But for other things like functions, there’s no corresponding runtime mechanism to identify their types. For example, consider this function:
对于某些值,例如基础类型string和number,我们可以在运行时使用typeof操作符识别它们的类型。但是对于函数等其他类型,没有相应的运行时机制来识别它们的类型。例如,考虑以下函数:
function fn(x) {return x.flip();}
We can observe by reading the code that this function will only work if given an object with a callable flip property, but JavaScript doesn’t surface this information in a way that we can check while the code is running. The only way in pure JavaScript to tell what fn does with a particular value is to call it and see what happens. This kind of behavior makes it hard to predict what code will do before it runs, which means it’s harder to know what your code is going to do while you’re writing it.
我们可以通过阅读代码来观察到,这个函数只有在给定一个具有可调用flip属性的对象时才会工作,但Javascript并没有以一种我们可以在代码运行时检查的方式来显示这个信息。在JavaScript中,告诉fn如何处理特定值的唯一方法是调用它并看发生了什么。这种行为使得在代码运行之前很难预测它会做什么,这意味着在编写代码时更难知道它会做什么。
Seen in this way, a type is the concept of describing which values can be passed to fn and which will crash. JavaScript only truly provides dynamic typing - running the code to see what happens.
从这个角度来看,类型是描述哪些值可以传递给fn,哪些值会崩溃的概念。Javascript只提供了动态类型——运行代码看看发生了什么。
The alternative is to use a static type system to make predictions about what code is expected before it runs.
另一种选择是使用静态类型系统,在运行代码之前对代码进行预测。
Static type-checking
静态类型检查
Think back to that TypeError we got earlier from trying to call a string as a function. Most people don’t like to get any sorts of errors when running their code - those are considered bugs! And when we write new code, we try our best to avoid introducing new bugs.
回想一下我们之前在尝试将string 作为函数调用时遇到的TypeError。大多数人在运行代码时不喜欢出现任何类型的错误——这些错误被认为是bug!当我们编写新代码时,我们会尽力避免引入新的bug。
If we add just a bit of code, save our file, re-run the code, and immediately see the error, we might be able to isolate the problem quickly; but that’s not always the case. We might not have tested the feature thoroughly enough, so we might never actually run into a potential error that would be thrown! Or if we were lucky enough to witness the error, we might have ended up doing large refactorings and adding a lot of different code that we’re forced to dig through.
如果我们添加一些代码,保存我们的文件,重新运行代码,并立即看到错误,我们或许能够快速剔除问题;但情况并不总是这样。我们可能没有对该特性进行足够全面的测试,所以我们可能永远不会遇到可能抛出的潜在错误!或者,如果我们足够幸运地目睹了这个错误,我们可能已经结束了大规模的重构,并添加了许多我们被迫挖掘的不同代码。
Ideally, we could have a tool that helps us find these bugs before our code runs. That’s what a static type-checker like TypeScript does. Static types systems describe the shapes and behaviors of what our values will be when we run our programs. A type-checker like TypeScript uses that information and tells us when things might be going off the rails.
理想情况下,我们可以有一个工具来帮助我们在代码运行之前找到这些错误。这就是像Typescript这样的静态类型检查器所做的。静态类型系统描述了在运行程序时我们的值的形状和行为。像TypeScript这样的检查器会使用这些信息,告诉我们什么时候可能会出错。
const message = "hello!";message();This expression is not callable.Type 'String' has no call signatures.
Running that last sample with TypeScript will give us an error message before we run the code in the first place.
在第一次运行代码之前,用TypeScript运行最后一个示例会给我们一个错误消息。
Non-exception Failures
非异常错误
So far we’ve been discussing certain things like runtime errors - cases where the JavaScript runtime tells us that it thinks something is nonsensical. Those cases come up because the ECMAScript specification has explicit instructions on how the language should behave when it runs into something unexpected.
到目前为止,我们已经讨论了一些像运行时的错误——JavaScript运行时告诉我们它认为一些事情是无意义的。出现这些情况是因为ECMAScript规范明确说明了语言在遇到意外情况时应该如何表现
For example, the specification says that trying to call something that isn’t callable should throw an error. Maybe that sounds like “obvious behavior”, but you could imagine that accessing a property that doesn’t exist on an object should throw an error too. Instead, JavaScript gives us different behavior and returns the value undefined:
例如,规范说,尝试调用不可调用的东西应该抛出错误。也许这听起来像是显而易见的行为,但您可以想象访问对象上不存在的属性也应该抛出错误,然而,JavaScript会给出不同的行为,并返回undefined:
const user = {name: "Daniel",age: 26,};user.location; // returns undefined
Ultimately, a static type system has to make the call over what code should be flagged as an error in its system, even if it’s “valid” JavaScript that won’t immediately throw an error. In TypeScript, the following code produces an error about location not being defined:
最终,静态类型系统必须调用系统中应该标记为错误的代码,即使它是不会立即抛出错误的“有效”JavaScript。在TypeScript中,以下代码会产生一个关于位置未定义的错误:
const user = {name: "Daniel",age: 26,};user.location;Property 'location' does not exist on type '{ name: string; age: number; }'
While sometimes that implies a trade-off in what you can express, the intent is to catch legitimate bugs in our programs. And TypeScript catches a lot of legitimate bugs.
虽然有时这意味着在可以表达的内容上需要权衡,但目的是捕获程序中正常的bug。TypeScript会捕获很多正常的bug。
For example: typos,
例如:拼写错误
const announcement = "Hello World!";// How quickly can you spot the typos?announcement.toLocaleLowercase();announcement.toLocalLowerCase();// We probably meant to write this...announcement.toLocaleLowerCase();
uncalled functions,
未调用的函数
function flipCoin() {// Meant to be Math.random()return Math.random < 0.5;// 运算符“<”不能应用于类型“() => number”和“number”}
or basic logic errors.
或者基本的逻辑错误
const value = Math.random() < 0.5 ? "a" : "b";if (value !== "a") {// ...} else if (value === "b") {This condition will always return 'false' since the types '"a"' and '"b"' have no overlap.// Oops, unreachable}
TypeScript can catch bugs when we make mistakes in our code. That’s great, but TypeScript can also prevent us from making those mistakes in the first place.
当我们在代码中出错时,Typescript可以捕捉到bug。这很好,但Typescript也可以从一开始就防止我们犯这些错误。
The type-checker has information to check things like whether we’re accessing the right properties on variables and other properties. Once it has that information, it can also start suggesting which properties you might want to use.
类型检查器有一些信息来检查一些比如我们是否正确访问了变量和其他的属性。一旦它有了这些信息,它也可以开始查询你可能不想使用的属性。
That means TypeScript can be leveraged for editing code too, and the core type-checker can provide error messages and code completion as you type in the editor. That’s part of what people often refer to when they talk about tooling in TypeScript.
这意味着TypeScript也可以用来编辑代码,当你在编辑器中输入时,核心类型检查器可以提供错误消息和带代码补全。这就是人们在谈到TypeScript中的工具时经常提到的部分内容。
sendsendDatesendfilesendFilesendStatus
TypeScript takes tooling seriously, and that goes beyond completions and errors as you type. An editor that supports TypeScript can deliver “quick fixes” to automatically fix errors, refactorings to easily re-organize code, and useful navigation features for jumping to definitions of a variable, or finding all references to a given variable. All of this is built on top of the type-checker and is fully cross-platform, so it’s likely that your favorite editor has TypeScript support available.
TypeScript非常重视工具的使用,而不仅仅是在你输入时代码补全和指出错误。一个支持Typescript的编辑器可以提供“快速修复”来自动修复错误,可以进行重构来方便地重新组织代码,还可以提供有用的导航功能来跳转到某个变量的定义,或者查找对给定变量的所有引用。所有这些都建立在类型检查器的基础上,并且是完全跨平台的,所以你喜欢的编辑器很可能有TypeScript支持。
tsc, the TypeScript compiler
tsc, TypeScript编译器
We’ve been talking about type-checking, but we haven’t yet used our type-checker. Let’s get acquainted with our new friend tsc, the TypeScript compiler. First we’ll need to grab it via npm.
我们一直在谈论类型检查,但我们还没有使用我们的类型检查器。让我们来认识一下我们的新朋友tsc, Typescript编译器。首先,我们需要通过npm获取它。
npm install -g typescript
This installs the TypeScript Compiler
tscglobally. You can usenpxor similar tools if you’d prefer to runtscfrom a localnode_modulespackage instead. 这将全局安装Typescript编译器tsc。如果你更喜欢在本地node_modules包中运行tsc,你可以使用npx或类似的工具。
Now let’s move to an empty folder and try writing our first TypeScript program: hello.ts:
现在让我们移动到一个空文件夹,尝试编写我们的第一个TypeScript程序:hello.ts
// Greets the world.console.log("Hello world!");
Notice there are no frills here; this “hello world” program looks identical to what you’d write for a “hello world” program in JavaScript. And now let’s type-check it by running the command tsc which was installed for us by the typescript package.
注意这里没有多余的东西;这个“hello world”程序看起来与你用JavaScript编写的“hello world”程序完全相同。现在让我们通过运行typescript包里我们安装的tsc命令来进行类型检查。
tsc hello.ts
Tada!
Wait, “tada” what exactly? We ran tsc and nothing happened! Well, there were no type errors, so we didn’t get any output in our console since there was nothing to report.
等等,”tada”到底是什么?我们运行tsc,什么都没发生!嗯,没有类型错误,所以我们没有得到任何输出在我们的控制台,因为没有什么报告。
But check again - we got some file output instead. If we look in our current directory, we’ll see a hello.js file next to hello.ts. That’s the output from our hello.ts file after tsc compiles or transforms it into a plain JavaScript file. And if we check the contents, we’ll see what TypeScript spits out after it processes a .ts file:
但是再检查一次——我们得到了一些文件输出。如果我们查看当前目录,我们会看到hello.ts旁边有一个hello.js文件。这是hello.ts在tsc编译或转换成纯JavaScript文件后生成的。如果我们检查它的内容,我们会看到TypeScript在处理一个.ts文件后会输出什么:
// Greets the world.console.log("Hello world!");
In this case, there was very little for TypeScript to transform, so it looks identical to what we wrote. The compiler tries to emit clean readable code that looks like something a person would write. While that’s not always so easy, TypeScript indents consistently, is mindful of when our code spans across different lines of code, and tries to keep comments around.
在这个例子中,TypeScript需要转换的内容很少,所以它看起来和我们写的一样。编译器试图发出干净可读的代码,看起来像人们编写的代码。虽然这并不总是那么容易,但TypeScript始终保持缩进,当我们的代码跨越不同的代码行时,它会注意,并尽量保留注释。
What about if we did introduce a type-checking error? Let’s rewrite hello.ts:
如果我们引入了一个类型检查错误呢?让我们重写hello.ts:
function greet(person, date) {console.log(`Hello ${person}, today is ${date}!`);}greet("Brendan");
If we run tsc hello.ts again, notice that we get an error on the command line!
如果我们运行tsc hello.ts,注意我们在命令行上得到一个错误!
Expected 2 arguments, but got 1.
TypeScript is telling us we forgot to pass an argument to the greet function, and rightfully so. So far we’ve only written standard JavaScript, and yet type-checking was still able to find problems with our code. Thanks TypeScript!
Typeścript告诉我们,我们忘记向greet函数传递一个参数,这是正确的。到目前为止,我们只编写了标准的JavaScript,但是类型检查仍然能够发现代码中的问题。感谢typescript!
Emitting with Errors
排除错误
One thing you might not have noticed from the last example was that our hello.js file changed again. If we open that file up then we’ll see that the contents still basically look the same as our input file. That might be a bit surprising given the fact that tsc reported an error about our code, but this is based on one of TypeScript’s core values: much of the time, you will know better than TypeScript.
在上一个示例中,您可能没有注意到的一点是,我们的hello.js文件再次发生了变化。如果我们打开那个文件,我们会看到它的内容基本上和我们的输入文件是一样的。考虑到tsc报告了一个关于我们代码的错误,这可能有点令人惊讶,但这是基于一个TypeScript的核心观念:大多数时候,你会比TypeScript更清楚。
To reiterate from earlier, type-checking code limits the sorts of programs you can run, and so there’s a tradeoff on what sorts of things a type-checker finds acceptable. Most of the time that’s okay, but there are scenarios where those checks get in the way. For example, imagine yourself migrating JavaScript code over to TypeScript and introducing type-checking errors. Eventually you’ll get around to cleaning things up for the type-checker, but that original JavaScript code was already working! Why should converting it over to TypeScript stop you from running it?
再说一遍,类型检查代码限制了您可以运行的程序的种类,因此在类型检查器认为可接受的内容的种类上有一个折衷。在大多数情况下,这是可以的,但在某些情况下,这些检查会成为障碍。例如,想象你将JavaScript代码迁移到TypeScript,并引入类型检查错误。最终,您会抽出时间去清理类型检查器东西,但最初的JavaScript代码已经在工作了!为什么转换成TypeScript会阻止你运行它呢?
So TypeScript doesn’t get in your way. Of course, over time, you may want to be a bit more defensive against mistakes, and make TypeScript act a bit more strictly. In that case, you can use the --noEmitOnError compiler option. Try changing your hello.ts file and running tsc with that flag:
这样TypeScript就不会妨碍你了。当然,随着时间的推移,您可能想要对错误有更多的防范,并让TypeScript的行为更严格一些。在这种情况下,可以使用——noEmitOnError编译器选项。尝试改变你的hello.ts文件和运行tsc命令:
tsc --noEmitOnError hello.ts
You’ll notice that hello.js never gets updated.
你会注意到hello.js永远不会被更新。
Explicit Types
显式类型
Up until now, we haven’t told TypeScript what person or date are. Let’s edit the code to tell TypeScript that person is a string, and that date should be a Date object. We’ll also use the toDateString() method on date.
到目前为止,我们还没有告诉Typescript什么是person 或date 。让我们编辑代码,告诉TypeScript person是一个字符串,date应该是一个Date对象。我们还将在date上使用toDatestring()方法
function greet(person: string, date: Date) {console.log(`Hello ${person}, today is ${date.toDateString()}!`);}
What we did was add type annotations on person and date to describe what types of values greet can be called with. You can read that signature as ”greet takes a person of type string, and a date of type Date“.
我们所做的是在person和date上添加类型注解来描述可以使用什么类型的值调用greet。您可以将该签名理解为“greet方法接受类型为string的person和类型为Date的date”
With this, TypeScript can tell us about other cases where we might have been called incorrectly. For example…
这样,TypeScript就可以告诉我们其他可能被错误调用的情况。例如. .
function greet(person: string, date: Date) {console.log(`Hello ${person}, today is ${date.toDateString()}!`);}greet("Maddison", Date());Argument of type 'string' is not assignable to parameter of type 'Date'.
Huh? TypeScript reported an error on our second argument, but why?
嗯?TypeScript报告了第二个参数的错误,但是为什么呢?
Perhaps surprisingly, calling Date() in JavaScript returns a string. On the other hand, constructing a Date with new Date() actually gives us what we were expecting.
也许令人惊讶的是,在Javascript中调用Date()会返回一个字符串。另一方面,用new Date()构造一个Date实际上得到了我们所期望的结果。
Anyway, we can quickly fix up the error:
无论如何,我们可以快速修正这个错误:
function greet(person: string, date: Date) {console.log(`Hello ${person}, today is ${date.toDateString()}!`);}greet("Maddison", new Date());
Keep in mind, we don’t always have to write explicit type annotations. In many cases, TypeScript can even just infer (or “figure out”) the types for us even if we omit them.
请记住,我们并不总是必须编写显式的类型注解。在很多情况下,TypeScript甚至可以为我们推断(或“算出”)这些类型,即使我们忽略了它们。
let msg = "hello there!";// ^ = let msg: string
Even though we didn’t tell TypeScript that msg had the type string it was able to figure that out. That’s a feature, and it’s best not to add annotations when the type system would end up inferring the same type anyway.
即使我们没有告诉TypeScriptmsg有字符串类型,它也能弄清楚。这是它一个特性,并且当类型系统最终推断出相同的类型时,最好不要添加注释。
Note: when you see
code comment colored like this
it means that we’re highlighting what your editor would show you inline. You can get the same experience in the web browser by hovering your mouse over blue-tinted code samples. 这意味着我们将在你的编辑器行内高亮显示。在web浏览器中,您可以通过将鼠标悬停在蓝色代码示例上获得相同的体验
Erased Types
删除类型
Let’s take a look at what happens when we compile the above function greet with tsc to output JavaScript:
让我们看看当我们用tsc编译上述函数greet以输出Javascript时会发生什么:
"use strict";function greet(person, date) {console.log("Hello " + person + ", today is " + date.toDateString() + "!");}greet("Maddison", new Date());
Notice two things here:
注意两件事:
- Our
personanddateparameters no longer have type annotations.
我们的person和date参数不再有类型注解。
- Our “template string” - that string that used backticks (the
`` character) - was converted to plain strings with concatenations (+`).
我们的“模板字符串”——使用反引号(`)的字符串——被转换为带有连接(+)的普通字符串。
More on that second point later, but let’s now focus on that first point. Type annotations aren’t part of JavaScript (or ECMAScript to be pedantic), so there really aren’t any browsers or other runtimes that can just run TypeScript unmodified. That’s why TypeScript needs a compiler in the first place - it needs some way to strip out or transform any TypeScript-specific code so that you can run it. Most TypeScript-specific code gets erased away, and likewise, here our type annotations were completely erased.
稍后再谈第二点,现在我们先来讨论第一点。类型注解不是JavaScript(或者ECMAScript)的一部分,所以没有任何浏览器或其他运行时可以不经过修改就运行Typescript。这就是为什么Typescript首先需要一个编译器——它需要一些方法来剥离或转换Typescript特有的代码,这样你就可以运行它了。大多数特定于typescript的代码会被删除,同样地,这里我们的类型注解也会被完全删除。
Remember: Type annotations never change the runtime behavior of your program. 记住:类型注释永远不会改变程序的运行时行为。
Downleveling
降低等级
One other difference from the above was that our template string was rewritten from
与上面的另一点不同之处在于我们的模板字符串被重写
`Hello ${person}, today is ${date.toDateString()}!`;
to
变成:
"Hello " + person + ", today is " + date.toDateString() + "!";
Why did this happen?
为什么会这样?
Template strings are a feature from a version of ECMAScript called ECMAScript 2015 (a.k.a. ECMAScript 6, ES2015, ES6, etc. - don’t ask). TypeScript has the ability to rewrite code from newer versions of ECMAScript to older ones such as ECMAScript 3 or ECMAScript 5 (a.k.a. ES3 and ES5). This process of moving from a newer or “higher” version of ECMAScript down to an older or “lower” one is sometimes called downleveling.
模板字符串是ECMAScript 2015版(也就是ES6)的一个特性。TypeScript可以将ECMAScript的新版本改写为ECMAScript 3或ECMAScript 5(也就是ES3和ES5)的旧版本。从较新的或“hiaher”版本的ECMAScript到较旧的或“较低”的一个有时被称为降低等级。
By default TypeScript targets ES3, an extremely old version of ECMAScript. We could have chosen something a little bit more recent by using the --target flag. Running with --target es2015 changes TypeScript to target ECMAScript 2015, meaning code should be able to run wherever ECMAScript 2015 is supported. So running tsc --target es2015 input.ts gives us the following output:
默认情况下,Typescript的目标是ES3,一个非常老的ECMAScript版本。我们本可以通过使用--target标志来选择更近一点的版本。使用--target es2015将TypeScript更改为目标ECMAScript 2015,这意味着代码应该能够在任何支持ECMAScript 2015的地方运行。因此运行tsc --target es2015 input.ts给出如下输出:
function greet(person, date) {console.log(`Hello ${person}, today is ${date.toDateString()}!`);}greet("Maddison", new Date());
While the default target is ES3, the great majority of current browsers support ES2015. Most developers can therefore safely specify ES2015 or above as a target, unless compatibility with certain ancient browsers is important. 虽然默认的目标是ES3,但目前大多数浏览器都支持ES2015。因此,大多数开发人员可以安全地指定ES2015或以上版本作为目标,除非与某些老式浏览器的兼容性非常重要
Strictness
严格
Different users come to TypeScript looking for different things in a type-checker. Some people are looking for a more loose opt-in experience which can help validate only some parts of their program, and still have decent tooling. This is the default experience with TypeScript, where types are optional, inference takes the most lenient types, and there’s no checking for potentially null/undefined values. Much like how tsc emits in the face of errors, these defaults are put in place to stay out of your way. If you’re migrating existing JavaScript, that might be a desirable first step.
不同的用户在Typescript中查找不同的内容。有些人正在寻找一种更宽松的体验,它只能帮助验证他们程序的某些部分,而且仍然有不错的工具。这是TypeScript的默认体验,类型是可选的,推断采用最宽松的类型,并且不会检查可能为null/undefined的值。就像tsc遇到错误时提出一样,这些默认项被放置在合适的位置,以避免妨碍你。如果您正在迁移现有的JavaScript,这可能是满足你的第一步。
In contrast, a lot of users prefer to have TypeScript validate as much as it can straight away, and that’s why the language provides strictness settings as well. These strictness settings turn static type-checking from a switch (either your code is checked or not) into something closer to a dial. The farther you turn this dial up, the more TypeScript will check for you. This can require a little extra work, but generally speaking it pays for itself in the long run, and enables more thorough checks and more accurate tooling. When possible, a new codebase should always turn these strictness checks on.
相比之下,很多用户更喜欢让Typescript尽可能直接地验证,这也是为什么该语言也提供了严格设置的原因。这些严格的设置将静态类型检查从开关(不管你的代码是否被选中)变成了更接近于刻度盘。你拨得越高,TypeScript就会为你检查更多。这可能需要一些额外的负荷,但总的来说,从长远来看,这是值得的,并支持更彻底的检查和更准确的工具。如果可能的话,新代码库应该总是开启这些严格的检查。
TypeScript has several type-checking strictness flags that can be turned on or off, and all of our examples will be written with all of them enabled unless otherwise stated. The --strict flag in the CLI, or "strict": true in a tsconfig.json toggles them all on simultaneously, but we can opt out of them individually. The two biggest ones you should know about are noImplicitAny and strictNullChecks.
Typescript有几个类型检查严格标记,可以打开或关闭,除非另有说明,否则我们所有的示例都将启用它们。CLI中的--strict标志,或者tsconfig.json中的"strict": true会同时打开它们,但是我们可以选择单独退出它们。你应该知道的两个最重要的配置是noImplicitAny and strictNullChecks.
noImplicitAny
Recall that in some places, TypeScript doesn’t try to infer any types for us and instead falls back to the most lenient type: any. This isn’t the worst thing that can happen - after all, falling back to any is just the plain JavaScript experience anyway.
回想一下,在某些地方,TypeScript不会试图为我们推断任何类型,而是退回到最宽松的类型:any。这并不是可能发生的最糟糕的事情——毕竟,退回到any只是普通的Javascript体验。
However, using any often defeats the purpose of using TypeScript in the first place. The more typed your program is, the more validation and tooling you’ll get, meaning you’ll run into fewer bugs as you code. Turning on the noImplicitAny flag will issue an error on any variables whose type is implicitly inferred as any.
然而,使用any通常首先就违背了使用TypeScript的目的。你的程序的类型越多,你得到的验证和工具就越多,这意味着你在编写代码时遇到的bug就越少。打开noImplicitAny标志会对任何隐式推断为any类型的变量发出错误
strictNullChecks
By default, values like null and undefined are assignable to any other type. This can make writing some code easier, but forgetting to handle null and undefined is the cause of countless bugs in the world - some consider it a billion dollar mistake! The strictNullChecks flag makes handling null and undefined more explicit, and spares us from worrying about whether we forgot to handle null and undefined.
默认情况下,像null和undefined这样的值可以分配给任何其他类型。这可以使编写一些代码更容易,但是忘记处理null和undefined是世界上无数错误的原因——一些人认为这是一个数十亿美元的错误!strictNullChecks标志使处理null和undefined更加显式,使我们不必担心是否忘记处理null和undefined。
