From 98cf67b0e7b9dfafae3204ba35d97c8cb1ad267a Mon Sep 17 00:00:00 2001 From: htmlin <10543563@qq.com> Date: Mon, 21 Jun 2021 23:09:01 +0800 Subject: [PATCH] docs(zh-Hans): translate docs/documentation/zh/handbook-v2/Everyday Types.md --- .../zh/handbook-v2/Everyday Types.md | 712 ++++++++++++++++++ 1 file changed, 712 insertions(+) create mode 100644 docs/documentation/zh/handbook-v2/Everyday Types.md diff --git a/docs/documentation/zh/handbook-v2/Everyday Types.md b/docs/documentation/zh/handbook-v2/Everyday Types.md new file mode 100644 index 00000000..38d14c87 --- /dev/null +++ b/docs/documentation/zh/handbook-v2/Everyday Types.md @@ -0,0 +1,712 @@ +--- +title: 日常类型 +layout: docs +permalink: /docs/handbook/2/everyday-types.html +oneline: "The language primitives." +--- + +在本章中,我们将介绍一些在 JavaScript 代码中最常见的值类型,并说明在 TypeScript 中描述这些类型相应的方法。 +这不是一个详尽的列表,后续章节将描述命名和使用其他类型的更多方法。 + +类型还可以出现在许多 _地方_ ,而不仅仅是类型注释。 +在我们了解类型本身的同时,我们还将了解在哪些地方可以引用这些类型来形成新的结构。 + +我们将首先回顾一下你在编写 JavaScript 或 TypeScript 代码时可能遇到的最基本和最常见的类型。 +这些将在稍后形成更复杂类型的核心构建块。 + +## The primitives: `string`, `number`, and `boolean` + +JavaScript has three very commonly used [primitives](https://developer.mozilla.org/en-US/docs/Glossary/Primitive): `string`, `number`, and `boolean`. +Each has a corresponding type in TypeScript. +As you might expect, these are the same names you'd see if you used the JavaScript `typeof` operator on a value of those types: + +- `string` represents string values like `"Hello, world"` +- `number` is for numbers like `42`. JavaScript does not have a special runtime value for integers, so there's no equivalent to `int` or `float` - everything is simply `number` +- `boolean` is for the two values `true` and `false` + +> The type names `String`, `Number`, and `Boolean` (starting with capital letters) are legal, but refer to some special built-in types that will very rarely appear in your code. _Always_ use `string`, `number`, or `boolean` for types. + +## Arrays + +To specify the type of an array like `[1, 2, 3]`, you can use the syntax `number[]`; this syntax works for any type (e.g. `string[]` is an array of strings, and so on). +You may also see this written as `Array`, which means the same thing. +We'll learn more about the syntax `T` when we cover _generics_. + +> Note that `[number]` is a different thing; refer to the section on _tuple types_. + +## `any` + +TypeScript also has a special type, `any`, that you can use whenever you don't want a particular value to cause typechecking errors. + +When a value is of type `any`, you can access any properties of it (which will in turn be of type `any`), call it like a function, assign it to (or from) a value of any type, or pretty much anything else that's syntactically legal: + +```ts twoslash +let obj: any = { x: 0 }; +// None of the following lines of code will throw compiler errors. +// Using `any` disables all further type checking, and it is assumed +// you know the environment better than TypeScript. +obj.foo(); +obj(); +obj.bar = 100; +obj = "hello"; +const n: number = obj; +``` + +The `any` type is useful when you don't want to write out a long type just to convince TypeScript that a particular line of code is okay. + +### `noImplicitAny` + +When you don't specify a type, and TypeScript can't infer it from context, the compiler will typically default to `any`. + +You usually want to avoid this, though, because `any` isn't type-checked. +Use the compiler flag [`noImplicitAny`](/tsconfig#noImplicitAny) to flag any implicit `any` as an error. + +## Type Annotations on Variables + +When you declare a variable using `const`, `var`, or `let`, you can optionally add a type annotation to explicitly specify the type of the variable: + +```ts twoslash +let myName: string = "Alice"; +// ^^^^^^^^ Type annotation +``` + +> TypeScript doesn't use "types on the left"-style declarations like `int x = 0;` +> Type annotations will always go _after_ the thing being typed. + +In most cases, though, this isn't needed. +Wherever possible, TypeScript tries to automatically _infer_ the types in your code. +For example, the type of a variable is inferred based on the type of its initializer: + +```ts twoslash +// No type annotation needed -- 'myName' inferred as type 'string' +let myName = "Alice"; +``` + +For the most part you don't need to explicitly learn the rules of inference. +If you're starting out, try using fewer type annotations than you think - you might be surprised how few you need for TypeScript to fully understand what's going on. + +## Functions + +Functions are the primary means of passing data around in JavaScript. +TypeScript allows you to specify the types of both the input and output values of functions. + +### Parameter Type Annotations + +When you declare a function, you can add type annotations after each parameter to declare what types of parameters the function accepts. +Parameter type annotations go after the parameter name: + +```ts twoslash +// Parameter type annotation +function greet(name: string) { + // ^^^^^^^^ + console.log("Hello, " + name.toUpperCase() + "!!"); +} +``` + +When a parameter has a type annotation, arguments to that function will be checked: + +```ts twoslash +// @errors: 2345 +declare function greet(name: string): void; +// ---cut--- +// Would be a runtime error if executed! +greet(42); +``` + +> Even if you don't have type annotations on your parameters, TypeScript will still check that you passed the right number of arguments. + +### Return Type Annotations + +You can also add return type annotations. +Return type annotations appear after the parameter list: + +```ts twoslash +function getFavoriteNumber(): number { + // ^^^^^^^^ + return 26; +} +``` + +Much like variable type annotations, you usually don't need a return type annotation because TypeScript will infer the function's return type based on its `return` statements. +The type annotation in the above example doesn't change anything. +Some codebases will explicitly specify a return type for documentation purposes, to prevent accidental changes, or just for personal preference. + +### Anonymous Functions + +Anonymous functions are a little bit different from function declarations. +When a function appears in a place where TypeScript can determine how it's going to be called, the parameters of that function are automatically given types. + +Here's an example: + +```ts twoslash +// @errors: 2551 +// No type annotations here, but TypeScript can spot the bug +const names = ["Alice", "Bob", "Eve"]; + +// Contextual typing for function +names.forEach(function (s) { + console.log(s.toUppercase()); +}); + +// Contextual typing also applies to arrow functions +names.forEach((s) => { + console.log(s.toUppercase()); +}); +``` + +Even though the parameter `s` didn't have a type annotation, TypeScript used the types of the `forEach` function, along with the inferred type of the array, to determine the type `s` will have. + +This process is called _contextual typing_ because the _context_ that the function occurred in informed what type it should have. +Similar to the inference rules, you don't need to explicitly learn how this happens, but understanding that it _does_ happen can help you notice when type annotations aren't needed. +Later, we'll see more examples of how the context that a value occurs in can affect its type. + +## Object Types + +Apart from primitives, the most common sort of type you'll encounter is an _object type_. +This refers to any JavaScript value with properties, which is almost all of them! +To define an object type, we simply list its properties and their types. + +For example, here's a function that takes a point-like object: + +```ts twoslash +// The parameter's type annotation is an object type +function printCoord(pt: { x: number; y: number }) { + // ^^^^^^^^^^^^^^^^^^^^^^^^ + console.log("The coordinate's x value is " + pt.x); + console.log("The coordinate's y value is " + pt.y); +} +printCoord({ x: 3, y: 7 }); +``` + +Here, we annotated the parameter with a type with two properties - `x` and `y` - which are both of type `number`. +You can use `,` or `;` to separate the properties, and the last separator is optional either way. + +The type part of each property is also optional. +If you don't specify a type, it will be assumed to be `any`. + +### Optional Properties + +Object types can also specify that some or all of their properties are _optional_. +To do this, add a `?` after the property name: + +```ts twoslash +function printName(obj: { first: string; last?: string }) { + // ... +} +// Both OK +printName({ first: "Bob" }); +printName({ first: "Alice", last: "Alisson" }); +``` + +In JavaScript, if you access a property that doesn't exist, you'll get the value `undefined` rather than a runtime error. +Because of this, when you _read_ from an optional property, you'll have to check for `undefined` before using it. + +```ts twoslash +// @errors: 2532 +function printName(obj: { first: string; last?: string }) { + // Error - might crash if 'obj.last' wasn't provided! + console.log(obj.last.toUpperCase()); + if (obj.last !== undefined) { + // OK + console.log(obj.last.toUpperCase()); + } + + // A safe alternative using modern JavaScript syntax: + console.log(obj.last?.toUpperCase()); +} +``` + +## Union Types + +TypeScript's type system allows you to build new types out of existing ones using a large variety of operators. +Now that we know how to write a few types, it's time to start _combining_ them in interesting ways. + +### Defining a Union Type + +The first way to combine types you might see is a _union_ type. +A union type is a type formed from two or more other types, representing values that may be _any one_ of those types. +We refer to each of these types as the union's _members_. + +Let's write a function that can operate on strings or numbers: + +```ts twoslash +// @errors: 2345 +function printId(id: number | string) { + console.log("Your ID is: " + id); +} +// OK +printId(101); +// OK +printId("202"); +// Error +printId({ myID: 22342 }); +``` + +### Working with Union Types + +It's easy to _provide_ a value matching a union type - simply provide a type matching any of the union's members. +If you _have_ a value of a union type, how do you work with it? + +TypeScript will only allow you to do things with the union if that thing is valid for _every_ member of the union. +For example, if you have the union `string | number`, you can't use methods that are only available on `string`: + +```ts twoslash +// @errors: 2339 +function printId(id: number | string) { + console.log(id.toUpperCase()); +} +``` + +The solution is to _narrow_ the union with code, the same as you would in JavaScript without type annotations. +_Narrowing_ occurs when TypeScript can deduce a more specific type for a value based on the structure of the code. + +For example, TypeScript knows that only a `string` value will have a `typeof` value `"string"`: + +```ts twoslash +function printId(id: number | string) { + if (typeof id === "string") { + // In this branch, id is of type 'string' + console.log(id.toUpperCase()); + } else { + // Here, id is of type 'number' + console.log(id); + } +} +``` + +Another example is to use a function like `Array.isArray`: + +```ts twoslash +function welcomePeople(x: string[] | string) { + if (Array.isArray(x)) { + // Here: 'x' is 'string[]' + console.log("Hello, " + x.join(" and ")); + } else { + // Here: 'x' is 'string' + console.log("Welcome lone traveler " + x); + } +} +``` + +Notice that in the `else` branch, we don't need to do anything special - if `x` wasn't a `string[]`, then it must have been a `string`. + +Sometimes you'll have a union where all the members have something in common. +For example, both arrays and strings have a `slice` method. +If every member in a union has a property in common, you can use that property without narrowing: + +```ts twoslash +// Return type is inferred as number[] | string +function getFirstThree(x: number[] | string) { + return x.slice(0, 3); +} +``` + +> It might be confusing that a _union_ of types appears to have the _intersection_ of those types' properties. +> This is not an accident - the name _union_ comes from type theory. +> The _union_ `number | string` is composed by taking the union _of the values_ from each type. +> Notice that given two sets with corresponding facts about each set, only the _intersection_ of those facts applies to the _union_ of the sets themselves. +> For example, if we had a room of tall people wearing hats, and another room of Spanish speakers wearing hats, after combining those rooms, the only thing we know about _every_ person is that they must be wearing a hat. + +## 类型别名 + +我们通过直接在类型注释中编写对象类型和联合类型来使用它们。 +这很方便,但是通常希望多次使用同一类型并使用单独的名称引用它。 + +一个 _类型别名_ 正是 - 任何 _类型_ 的一个 _名称_ 。 +类型别名的语法是: + +```ts twoslash +type Point = { + x: number; + y: number; +}; + +// 与前面的示例完全相同 +function printCoord(pt: Point) { + console.log("The coordinate's x value is " + pt.x); + console.log("The coordinate's y value is " + pt.y); +} + +printCoord({ x: 100, y: 100 }); +``` + +实际上,你可以使用类型别名为任何类型命名,而不仅仅是对象类型。 +例如,类型别名可以命名联合类型: + +```ts twoslash +type ID = number | string; +``` + +请注意,别名 _只是_ 别名 - 你不能使用类型别名创建同一类型的不同“版本”。 +当你使用别名时,它与您编写的别名类型完全一样。 +换句话说,这段代码 _看起来_ 可能是非法的,但根据 TypeScript 来说是可以的,因为这两种类型都是同一类型的别名: + +```ts twoslash +declare function getInput(): string; +declare function sanitize(str: string): string; +// ---分割--- +type UserInputSanitizedString = string; + +function sanitizeInput(str: string): UserInputSanitizedString { + return sanitize(str); +} + +// 创建一个经过清理的输入框 +let userInput = sanitizeInput(getInput()); + +// 仍然可以使用字符串重新赋值 +userInput = "new input"; +``` + +## 接口 + +_接口声明_ 是命名对象类型的另一种方式: + +```ts twoslash +interface Point { + x: number; + y: number; +} + +function printCoord(pt: Point) { + console.log("The coordinate's x value is " + pt.x); + console.log("The coordinate's y value is " + pt.y); +} + +printCoord({ x: 100, y: 100 }); +``` + +就像我们上面使用类型别名时一样,这个示例的工作方式就像我们使用了匿名对象类型一样。 +TypeScript 只关心我们传递给 `printCoord` 的值的结构 - 它只关心它是否具有预期的属性。 +只关心类型的结构和功能,这就是为什么我们说 TypeScript 是一个 _结构化类型_ 的类型系统。 + +### 类型别名和接口之间的区别 + +类型别名和接口非常相似,在大多数情况下你可以在它们之间自由选择。 +几乎所有的 `interface` 功能都可以在 `type` 中使用,关键区别在于不能重新打开类型以添加新的属性,而接口始终是可扩展的。 + + + + + + + + + + + + + + + + +
InterfaceType
+

扩展接口

+
+interface Animal {
+  name: string
+}
+interface Bear extends Animal { + honey: boolean +}
+const bear = getBear() +bear.name +bear.honey +
+
+

通过 "&" 扩展类型

+
+type Animal = {
+  name: string
+}
+type Bear = Animal & { + honey: Boolean +}
+const bear = getBear(); +bear.name; +bear.honey; +
+
+

向现有接口添加新字段

+
+interface Window {
+  title: string
+}
+interface Window { + ts: TypeScriptAPI +}
+const src = 'const a = "Hello World"'; +window.ts.transpileModule(src, {}); +
+
+

类型创建后不能更改

+
+type Window = {
+  title: string
+}
+type Window = { + ts: TypeScriptAPI +}
+ // Error: Duplicate identifier 'Window'.
+
+
+ +在后面的章节中你会学到更多关于这些概念的知识,所以如果你没有立即理解这些知识,请不要担心。 + +- 在 TypeScript 4.2 之前,类型别名命名 [_可能_ 会出现在错误消息中](/play?#code/PTAEGEHsFsAcEsA2BTATqNrLusgzngIYDm+oA7koqIYuYQJ56gCueyoAUCKAC4AWHAHaFcoSADMaQ0PCG80EwgGNkALk6c5C1EtWgAsqOi1QAb06groEbjWg8vVHOKcAvpokshy3vEgyyMr8kEbQJogAFND2YREAlOaW1soBeJAoAHSIkMTRmbbI8e6aPMiZxJmgACqCGKhY6ABGyDnkFFQ0dIzMbBwCwqIccabcYLyQoKjIEmh8kwN8DLAc5PzwwbLMyAAeK77IACYaQSEjUWZWhfYAjABMAMwALA+gbsVjoADqgjKESytQPxCHghAByXigYgBfr8LAsYj8aQMUASbDQcRSExCeCwFiIQh+AKfAYyBiQFgOPyIaikSGLQo0Zj-aazaY+dSaXjLDgAGXgAC9CKhDqAALxJaw2Ib2RzOISuDycLw+ImBYKQflCkWRRD2LXCw6JCxS1JCdJZHJ5RAFIbFJU8ADKC3WzEcnVZaGYE1ABpFnFOmsFhsil2uoHuzwArO9SmAAEIsSFrZB-GgAjjA5gtVN8VCEc1o1C4Q4AGlR2AwO1EsBQoAAbvB-gJ4HhPgB5aDwem-Ph1TCV3AEEirTp4ELtRbTPD4vwKjOfAuioSQHuDXBcnmgACC+eCONFEs73YAPGGZVT5cRyyhiHh7AAON7lsG3vBggB8XGV3l8-nVISOgghxoLq9i7io-AHsayRWGaFrlFauq2rg9qaIGQHwCBqChtKdgRo8TxRjeyB3o+7xAA),有时代替等效的匿名类型(可能需要也可能不需要)。接口在错误消息中将始终被命名。 +- 类型别名不能参与 [声明合并,但接口可以](/play?#code/PTAEEEDtQS0gXApgJwGYEMDGjSfdAIx2UQFoB7AB0UkQBMAoEUfO0Wgd1ADd0AbAK6IAzizp16ALgYM4SNFhwBZdAFtV-UAG8GoPaADmNAcMmhh8ZHAMMAvjLkoM2UCvWad+0ARL0A-GYWVpA29gyY5JAWLJAwGnxmbvGgALzauvpGkCZmAEQAjABMAMwALLkANBl6zABi6DB8okR4Jjg+iPSgABboovDk3jjo5pbW1d6+dGb5djLwAJ7UoABKiJTwjThpnpnGpqPBoTLMAJrkArj4kOTwYmycPOhW6AR8IrDQ8N04wmo4HHQCwYi2Waw2W1S6S8HX8gTGITsQA)。 +- 接口只能用于 [声明对象,不能重命名基本类型](/play?#code/PTAEAkFMCdIcgM6gC4HcD2pIA8CGBbABwBtIl0AzUAKBFAFcEBLAOwHMUBPQs0XFgCahWyGBVwBjMrTDJMAshOhMARpD4tQ6FQCtIE5DWoixk9QEEWAeV37kARlABvaqDegAbrmL1IALlAEZGV2agBfampkbgtrWwMAJlAAXmdXdy8ff0Dg1jZwyLoAVWZ2Lh5QVHUJflAlSFxROsY5fFAWAmk6CnRoLGwmILzQQmV8JmQmDzI-SOiKgGV+CaYAL0gBBdyy1KCQ-Pn1AFFplgA5enw1PtSWS+vCsAAVAAtB4QQWOEMKBuYVUiVCYvYQsUTQcRSBDGMGmKSgAAa-VEgiQe2GLgKQA). +- 接口名称将 [_始终_ 以其原始形式出现](/play?#code/PTAEGEHsFsAcEsA2BTATqNrLusgzngIYDm+oA7koqIYuYQJ56gCueyoAUCKAC4AWHAHaFcoSADMaQ0PCG80EwgGNkALk6c5C1EtWgAsqOi1QAb06groEbjWg8vVHOKcAvpokshy3vEgyyMr8kEbQJogAFND2YREAlOaW1soBeJAoAHSIkMTRmbbI8e6aPMiZxJmgACqCGKhY6ABGyDnkFFQ0dIzMbBwCwqIccabcYLyQoKjIEmh8kwN8DLAc5PzwwbLMyAAeK77IACYaQSEjUWY2Q-YAjABMAMwALA+gbsVjNXW8yxySoAADaAA0CCaZbPh1XYqXgOIY0ZgmcK0AA0nyaLFhhGY8F4AHJmEJILCWsgZId4NNfIgGFdcIcUTVfgBlZTOWC8T7kAJ42G4eT+GS42QyRaYbCgXAEEguTzeXyCjDBSAAQSE8Ai0Xsl0K9kcziExDeiQs1lAqSE6SyOTy0AKQ2KHk4p1V6s1OuuoHuzwArMagA) 在错误消息中,但 _只有_ 在按名称使用时才会出现。 + +在大多数情况下,你可以根据个人喜好进行选择,TypeScript 会告诉你它是否需要其他类型的声明。如果您想要启发式方法,可以使用 `interface` 直到你需要使用 `type` 中的功能。 + +## Type Assertions + +Sometimes you will have information about the type of a value that TypeScript can't know about. + +For example, if you're using `document.getElementById`, TypeScript only knows that this will return _some_ kind of `HTMLElement`, but you might know that your page will always have an `HTMLCanvasElement` with a given ID. + +In this situation, you can use a _type assertion_ to specify a more specific type: + +```ts twoslash +const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement; +``` + +Like a type annotation, type assertions are removed by the compiler and won't affect the runtime behavior of your code. + +You can also use the angle-bracket syntax (except if the code is in a `.tsx` file), which is equivalent: + +```ts twoslash +const myCanvas = document.getElementById("main_canvas"); +``` + +> Reminder: Because type assertions are removed at compile-time, there is no runtime checking associated with a type assertion. +> There won't be an exception or `null` generated if the type assertion is wrong. + +TypeScript only allows type assertions which convert to a _more specific_ or _less specific_ version of a type. +This rule prevents "impossible" coercions like: + +```ts twoslash +// @errors: 2352 +const x = "hello" as number; +``` + +Sometimes this rule can be too conservative and will disallow more complex coercions that might be valid. +If this happens, you can use two assertions, first to `any` (or `unknown`, which we'll introduce later), then to the desired type: + +```ts twoslash +declare const expr: any; +type T = { a: 1; b: 2; c: 3 }; +// ---cut--- +const a = expr as any as T; +``` + +## Literal Types + +In addition to the general types `string` and `number`, we can refer to _specific_ strings and numbers in type positions. + +One way to think about this is to consider how JavaScript comes with different ways to declare a variable. Both `var` and `let` allow for changing what is held inside the variable, and `const` does not. This is reflected in how TypeScript creates types for literals. + +```ts twoslash +let changingString = "Hello World"; +changingString = "Olá Mundo"; +// Because `changingString` can represent any possible string, that +// is how TypeScript describes it in the type system +changingString; +// ^? + +const constantString = "Hello World"; +// Because `constantString` can only represent 1 possible string, it +// has a literal type representation +constantString; +// ^? +``` + +By themselves, literal types aren't very valuable: + +```ts twoslash +// @errors: 2322 +let x: "hello" = "hello"; +// OK +x = "hello"; +// ... +x = "howdy"; +``` + +It's not much use to have a variable that can only have one value! + +But by _combining_ literals into unions, you can express a much more useful concept - for example, functions that only accept a certain set of known values: + +```ts twoslash +// @errors: 2345 +function printText(s: string, alignment: "left" | "right" | "center") { + // ... +} +printText("Hello, world", "left"); +printText("G'day, mate", "centre"); +``` + +Numeric literal types work the same way: + +```ts twoslash +function compare(a: string, b: string): -1 | 0 | 1 { + return a === b ? 0 : a > b ? 1 : -1; +} +``` + +Of course, you can combine these with non-literal types: + +```ts twoslash +// @errors: 2345 +interface Options { + width: number; +} +function configure(x: Options | "auto") { + // ... +} +configure({ width: 100 }); +configure("auto"); +configure("automatic"); +``` + +There's one more kind of literal type: boolean literals. +There are only two boolean literal types, and as you might guess, they are the types `true` and `false`. +The type `boolean` itself is actually just an alias for the union `true | false`. + +### Literal Inference + +When you initialize a variable with an object, TypeScript assumes that the properties of that object might change values later. +For example, if you wrote code like this: + +```ts twoslash +declare const someCondition: boolean; +// ---cut--- +const obj = { counter: 0 }; +if (someCondition) { + obj.counter = 1; +} +``` + +TypeScript doesn't assume the assignment of `1` to a field which previously had `0` is an error. +Another way of saying this is that `obj.counter` must have the type `number`, not `0`, because types are used to determine both _reading_ and _writing_ behavior. + +The same applies to strings: + +```ts twoslash +// @errors: 2345 +declare function handleRequest(url: string, method: "GET" | "POST"): void; +// ---cut--- +const req = { url: "https://example.com", method: "GET" }; +handleRequest(req.url, req.method); +``` + +In the above example `req.method` is inferred to be `string`, not `"GET"`. Because code can be evaluated between the creation of `req` and the call of `handleRequest` which could assign a new string like `"GUESS"` to `req.method`, TypeScript considers this code to have an error. + +There are two ways to work around this. + +1. You can change the inference by adding a type assertion in either location: + + ```ts twoslash + declare function handleRequest(url: string, method: "GET" | "POST"): void; + // ---cut--- + // Change 1: + const req = { url: "https://example.com", method: "GET" as "GET" }; + // Change 2 + handleRequest(req.url, req.method as "GET"); + ``` + + Change 1 means "I intend for `req.method` to always have the _literal type_ `"GET"`", preventing the possible assignment of `"GUESS"` to that field after. + Change 2 means "I know for other reasons that `req.method` has the value `"GET"`". + +2. You can use `as const` to convert the entire object to be type literals: + + ```ts twoslash + declare function handleRequest(url: string, method: "GET" | "POST"): void; + // ---cut--- + const req = { url: "https://example.com", method: "GET" } as const; + handleRequest(req.url, req.method); + ``` + +The `as const` suffix acts like `const` but for the type system, ensuring that all properties are assigned the literal type instead of a more general version like `string` or `number`. + +## `null` and `undefined` + +JavaScript has two primitive values used to signal absent or uninitialized value: `null` and `undefined`. + +TypeScript has two corresponding _types_ by the same names. How these types behave depends on whether you have the `strictNullChecks` option on. + +### `strictNullChecks` off + +With `strictNullChecks` _off_, values that might be `null` or `undefined` can still be accessed normally, and the values `null` and `undefined` can be assigned to a property of any type. +This is similar to how languages without null checks (e.g. C#, Java) behave. +The lack of checking for these values tends to be a major source of bugs; we always recommend people turn `strictNullChecks` on if it's practical to do so in their codebase. + +### `strictNullChecks` on + +With `strictNullChecks` _on_, when a value is `null` or `undefined`, you will need to test for those values before using methods or properties on that value. +Just like checking for `undefined` before using an optional property, we can use _narrowing_ to check for values that might be `null`: + +```ts twoslash +function doSomething(x: string | null) { + if (x === null) { + // do nothing + } else { + console.log("Hello, " + x.toUpperCase()); + } +} +``` + +### Non-null Assertion Operator (Postfix `!`) + +TypeScript also has a special syntax for removing `null` and `undefined` from a type without doing any explicit checking. +Writing `!` after any expression is effectively a type assertion that the value isn't `null` or `undefined`: + +```ts twoslash +function liveDangerously(x?: number | null) { + // No error + console.log(x!.toFixed()); +} +``` + +Just like other type assertions, this doesn't change the runtime behavior of your code, so it's important to only use `!` when you know that the value _can't_ be `null` or `undefined`. + +## Enums + +Enums are a feature added to JavaScript by TypeScript which allows for describing a value which could be one of a set of possible named constants. Unlike most TypeScript features, this is _not_ a type-level addition to JavaScript but something added to the language and runtime. Because of this, it's a feature which you should know exists, but maybe hold off on using unless you are sure. You can read more about enums in the [Enum reference page](/docs/handbook/enums.html). + +## Less Common Primitives + +It's worth mentioning the rest of the primitives in JavaScript which are represented in the type system. +Though we will not go into depth here. + +##### `bigint` + +From ES2020 onwards, there is a primitive in JavaScript used for very large integers, `BigInt`: + +```ts twoslash +// @target: es2020 + +// Creating a bigint via the BigInt function +const oneHundred: bigint = BigInt(100); + +// Creating a BigInt via the literal syntax +const anotherHundred: bigint = 100n; +``` + +You can learn more about BigInt in [the TypeScript 3.2 release notes](/docs/handbook/release-notes/typescript-3-2.html#bigint). + +##### `symbol` + +There is a primitive in JavaScript used to create a globally unique reference via the function `Symbol()`: + +```ts twoslash +// @errors: 2367 +const firstName = Symbol("name"); +const secondName = Symbol("name"); + +if (firstName === secondName) { + // Can't ever happen +} +``` + +You can learn more about them in [Symbols reference page](/docs/handbook/symbols.html).