| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
Thanks for the PR! This section of the codebase is owned by Kibeom Kwon (@bumkeyy), YeonJuan (@yeonjuan), Dan Jeong (@guyeol), and Seohee Park (@dvlprsh) - if they write a comment saying "LGTM" then it will be merged. |
Sorry, something went wrong.
|
Translation of TypeScript 4.9.md
title: TypeScript 4.9 oneline: TypeScript 4.9 Release NotesThe satisfies OperatorTypeScript developers are often faced with a dilemma: we want to ensure that some expression matches some type, but also want to keep the most specific type of that expression for inference purposes. For example: // Each property can be a string or an RGB tuple.
const palette = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255]
// ^^^^ sacrebleu - we've made a typo!
};
// We want to be able to use array methods on 'red'...
const redComponent = palette.red.at(0);
// or string methods on 'green'...
const greenNormalized = palette.green.toUpperCase();Notice that we've written bleu, whereas we probably should have written blue. type Colors = "red" | "green" | "blue";
type RGB = [red: number, green: number, blue: number];
const palette: Record<Colors, string | RGB> = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255]
// ~~~~ The typo is now correctly detected
};
// But we now have an undesirable error here - 'palette.red' "could" be a string.
const redComponent = palette.red.at(0);The new satisfies operator lets us validate that the type of an expression matches some type, without changing the resulting type of that expression. type Colors = "red" | "green" | "blue";
type RGB = [red: number, green: number, blue: number];
const palette = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255]
// ~~~~ The typo is now caught!
} satisfies Record<Colors, string | RGB>;
// Both of these methods are still accessible!
const redComponent = palette.red.at(0);
const greenNormalized = palette.green.toUpperCase();satisfies can be used to catch lots of possible errors. type Colors = "red" | "green" | "blue";
// Ensure that we have exactly the keys from 'Colors'.
const favoriteColors = {
"red": "yes",
"green": false,
"blue": "kinda",
"platypus": false
// ~~~~~~~~~~ error - "platypus" was never listed in 'Colors'.
} satisfies Record<Colors, unknown>;
// All the information about the 'red', 'green', and 'blue' properties are retained.
const g: boolean = favoriteColors.green;Maybe we don't care about if the property names match up somehow, but we do care about the types of each property. type RGB = [red: number, green: number, blue: number];
const palette = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0]
// ~~~~~~ error!
} satisfies Record<string, string | RGB>;
// Information about each property is still maintained.
const redComponent = palette.red.at(0);
const greenNormalized = palette.green.toUpperCase();For more examples, you can see the issue proposing this and the implementing pull request. Unlisted Property Narrowing with the in OperatorAs developers, we often need to deal with values that aren't fully known at runtime. Previously, TypeScript allowed us to narrow away any types that don't explicitly list a property. interface RGB {
red: number;
green: number;
blue: number;
}
interface HSV {
hue: number;
saturation: number;
value: number;
}
function setColor(color: RGB | HSV) {
if ("hue" in color) {
// 'color' now has the type HSV
}
// ...
}Here, the type RGB didn't list the hue and got narrowed away, and leaving us with the type HSV. But what about examples where no type listed a given property? function tryGetPackageName(context) {
const packageJSON = context.packageJSON;
// Check to see if we have an object.
if (packageJSON && typeof packageJSON === "object") {
// Check to see if it has a string name property.
if ("name" in packageJSON && typeof packageJSON.name === "string") {
return packageJSON.name;
}
}
return undefined;
}Rewriting this to canonical TypeScript would just be a matter of defining and using a type for context; interface Context {
packageJSON: unknown;
}
function tryGetPackageName(context: Context) {
const packageJSON = context.packageJSON;
// Check to see if we have an object.
if (packageJSON && typeof packageJSON === "object") {
// Check to see if it has a string name property.
if ("name" in packageJSON && typeof packageJSON.name === "string") {
// ~~~~
// error! Property 'name' does not exist on type 'object.
return packageJSON.name;
// ~~~~
// error! Property 'name' does not exist on type 'object.
}
}
return undefined;
}This is because while the type of packageJSON was narrowed from unknown to object, the in operator strictly narrowed to types that actually defined the property being checked. TypeScript 4.9 makes the in operator a little bit more powerful when narrowing types that don't list the property at all. So in our example, packageJSON will have its type narrowed from unknown to object to object & Record<"name", unknown> interface Context {
packageJSON: unknown;
}
function tryGetPackageName(context: Context): string | undefined {
const packageJSON = context.packageJSON;
// Check to see if we have an object.
if (packageJSON && typeof packageJSON === "object") {
// Check to see if it has a string name property.
if ("name" in packageJSON && typeof packageJSON.name === "string") {
// Just works!
return packageJSON.name;
}
}
return undefined;
}TypeScript 4.9 also tightens up a few checks around how in is used, ensuring that the left side is assignable to the type string | number | symbol, and the right side is assignable to object. For more information, read the implementing pull request Auto-Accessors in ClassesTypeScript 4.9 supports an upcoming feature in ECMAScript called auto-accessors. class Person {
accessor name: string;
constructor(name: string) {
this.name = name;
}
}Under the covers, these auto-accessors "de-sugar" to a get and set accessor with an unreachable private property. class Person {
#__name: string;
get name() {
return this.#__name;
}
set name(value: string) {
this.#__name = name;
}
constructor(name: string) {
this.name = name;
}
}You can [read up more about the auto-accessors pull request on the original PR](https://github.com/microsoft/TypeScript/pull/49705). Checks For Equality on NaNA major gotcha for JavaScript developers is checking against the value NaN using the built-in equality operators. For some background, NaN is a special numeric value that stands for "Not a Number". console.log(NaN == 0) // false
console.log(NaN === 0) // false
console.log(NaN == NaN) // false
console.log(NaN === NaN) // falseBut at least symmetrically everything is always not-equal to NaN. console.log(NaN != 0) // true
console.log(NaN !== 0) // true
console.log(NaN != NaN) // true
console.log(NaN !== NaN) // trueThis technically isn't a JavaScript-specific problem, since any language that contains IEEE-754 floats has the same behavior; TypeScript now errors on direct comparisons against NaN, and will suggest using some variation of Number.isNaN instead. function validate(someValue: number) {
return someValue !== NaN;
// ~~~~~~~~~~~~~~~~~
// error: This condition will always return 'true'.
// Did you mean '!Number.isNaN(someValue)'?
}We believe that this change should strictly help catch beginner errors, similar to how TypeScript currently issues errors on comparisons against object and array literals. We'd like to extend our thanks to [Oleksandr Tarasiuk](https://github.com/a-tarasyuk) who [contributed this check](https://github.com/microsoft/TypeScript/pull/50626). File-Watching Now Uses File System EventsIn earlier versions, TypeScript leaned heavily on polling for watching individual files. Generally speaking, a better approach is to use file system events. As a result, our default was to pick the lowest common denominator: polling. Over time, we've provided the means to [choose other file-watching strategies](https://www.typescriptlang.org/docs/handbook/configuring-watch.html). In TypeScript 4.9, file watching is powered by file system events by default, only falling back to polling if we fail to set up event-based watchers. [The way file-watching works can still be configured] (https://www.typescriptlang.org/docs/handbook/configuring-watch.html) through environment variables and watchOptions - and [some editors like VS Code can support watchOptions independently](https://code.visualstudio.com/docs/getstarted/settings#:~:text=typescript%2etsserver%2ewatchOptions). You can [read up more on this change on GitHub](https://github.com/microsoft/TypeScript/pull/50366). "Remove Unused Imports" and "Sort Imports" editor commandsSo far, TypeScript has supported only two editor commands for managing imports. import { Zebra, Moose, HoneyBadger } from "./zoo";
import { foo, bar } from "./helper";
let x: Moose | HoneyBadger = foo();First, "Organize Imports" removes unused imports and sorts the remaining imports. import { foo } from "./helper";
import { HoneyBadger, Moose } from "./zoo";
let x: Moose | HoneyBadger = foo();In TypeScript 4.3, import within a file only "Sort Imports", which only sorts but does not remove, has been introduced. This rewrites the file as: import { bar, foo } from "./helper";
import { HoneyBadger, Moose, Zebra } from "./zoo";
let x: Moose | HoneyBadger = foo();A note about "Sort Imports" is that in Visual Studio Code, this feature was only available as an on-save command, not as a command that could be triggered manually. TypeScript 4.9 added the other half and now provides the "Remove Unused Imports" feature. import { Moose, HoneyBadger } from "./zoo";
import { foo } from "./helper";
let x: Moose | HoneyBadger = foo();This feature is available in any editor that wants to use both commands. [Details of this feature here] (https://github.com/microsoft/TypeScript/pull/50931). return Go-to-Definition for KeywordsTypeScript is now in the editor return Once the go-to-definition function for the keyword is performed, it allows you to move to the top of the function. TypeScript uses this function as [awaitand yield](https://github.com/microsoft/TypeScript/issues/51223) or [switch, caseand default] (https://github.com/microsoft/TypeScript/issues/51225). [Oleksandr Tarasiuk] Thanks to (https://github.com/a-tarasyuk), [this function has been implemented] (https://github.com/microsoft/TypeScript/pull/51227). Performance improvementsTypeScript has several small but notable performance improvements. First, in all syntax nodes switch Use a function table lookup instead of a statement in TypeScript forEachChild The function has been refactored. forEachChildAfter you see the performance improvements for the NodeT visitEachChildI tried refactoring in . forEachChild's initial exploration was inspired by [blog posts] (https://artemis.sh/2022/08/07/emulating-calculators-fast-in-js.html) by [Artemis Everfree] (https://artemis.sh/). Finally, we've optimized the way TypeScript preserves information about types in the actual branch of conditional types. interface Zoo<T extends Animal> {
// ...
}
type MakeZoo<A> = A extends Animal ? Zoo<A> : never;TypeScript is Zoo<A>When checking if is valid ADegree AnimalYou have to "remember" that it should be. You can learn more about it in each pull request.
Correctness Fixes and Breaking Changeslib.d.ts UpdatesWhile TypeScript strives to avoid major breaks, even small changes in the built-in libraries can cause issues. Better Types for Promise.resolvePromise.resolve now uses the Awaited type to unwrap Promise-like types passed to it. JavaScript Emit No Longer Elides ImportsWhen TypeScript first supported type-checking and compilation for JavaScript, it accidentally supported a feature called import elision. This behavior was questionable, especially the detection of whether the import doesn't refer to a value, since it means that TypeScript has to trust sometimes-inaccurate declaration files. // Input:
import { someValue, SomeClass } from "some-module";
/** @type {SomeClass} */
let val = someValue;
// Previous Output:
import { someValue } from "some-module";
/** @type {SomeClass} */
let val = someValue;
// Current Output:
import { someValue, SomeClass } from "some-module";
/** @type {SomeClass} */
let val = someValue;More information is available at [the implementing change](https://github.com/microsoft/TypeScript/pull/50404). exports is Prioritized Over typesVersionsPreviously, TypeScript incorrectly prioritized the typesVersions field over the exports field when resolving through a package.json under --moduleResolution node16. {
"type": "module",
"main": "./dist/main.js"
"typesVersions": {
"<4.8": { ".": ["4.8-types/main.d.ts"] },
"*": { ".": ["modern-types/main.d.ts"] }
},
"exports": {
".": {
+ "types@<4.8": "4.8-types/main.d.ts",
+ "types": "modern-types/main.d.ts",
"import": "./dist/main.js"
}
}
}For more information, [see this pull request](https://github.com/microsoft/TypeScript/pull/50890). substitute Replaced With constraint on SubstitutionTypesAs part of an optimization on substitution types, SubstitutionType objects no longer contain the substitute property representing the effective substitution (usually an intersection of the base type and the implicit constraint) - instead, they just contain the constraint property. For more details, [read more on the original pull request](https://github.com/microsoft/TypeScript/pull/50397). |
Sorry, something went wrong.
|
@microsoft-github-policy-service agree |
Sorry, something went wrong.
| The first was called "Organize Imports" which would remove unused imports, and then sort the remaining ones. | ||
| It would rewrite that file to look like this one: | ||
| 첫 번째는 사용되지 않는 import 를 제거하고 남은 import 를 정렬하는 "Organize Imports" 입니다. | ||
| 이것은 파일을 다음과 같이 재작성합니다. |
There was a problem hiding this comment.
| 이것은 파일을 다음과 같이 재작성합니다. | |
| 이것은 파일을 다음 예시 코드처럼 재작성합니다. |
[제안]
Sorry, something went wrong.
|
@swimmee 번역 감사합니다 👍 |
Sorry, something went wrong.
|
Kibeom Kwon (@bumkeyy) 리뷰 감사합니다👍 반영해보았는데 확인부탁드립니다! |
Sorry, something went wrong.
|
LGTM |
Sorry, something went wrong.
|
Merging because Kibeom Kwon (@bumkeyy) is a code-owner of all the changes - thanks! |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
No description provided.