diff --git a/docusaurus.config.js b/docusaurus.config.js index 0f7ed98..1956f90 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -24,6 +24,9 @@ const config = { .readFileSync(path.join(articlesBaseDir, file)) .toString(); + if (!/meta: (.+)/.exec(contents)) { + console.log({ file, contents }); + } return { date: /date: "(.+)"/.exec(contents)[1], description: /description: "(.+)"/.exec(contents)[1], @@ -113,6 +116,8 @@ const config = { editUrl: "https://github.com/JoshuaKGoldberg/learning-typescript/tree/main/", path: "src/content/articles", + readingTime: (args) => + Math.ceil(Math.pow(args.defaultReadingTime(args), 1.5) / 5) * 5, routeBasePath: "articles", showReadingTime: true, }, @@ -131,6 +136,16 @@ const config = { }, }), ], + [ + "docusaurus-preset-shiki-twoslash", + { + defaultCompilerOptions: { + lib: ["dom", "es2021"], + target: "esnext", + }, + themes: ["min-light", "nord"], + }, + ], ], themeConfig: diff --git a/package.json b/package.json index 59da093..780b18a 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@mdx-js/react": "^1.6.22", "@swc/core": "^1.2.194", "clsx": "^1.1.1", + "docusaurus-preset-shiki-twoslash": "^1.1.38", "fs-readdir-recursive": "^1.1.0", "konamimojisplosion": "^0.5.1", "mdast-util-from-markdown": "^1.2.0", diff --git a/src/content/articles/for-in-string-types.mdx b/src/content/articles/for-in-string-types.mdx new file mode 100644 index 0000000..7195f9f --- /dev/null +++ b/src/content/articles/for-in-string-types.mdx @@ -0,0 +1,225 @@ +--- +date: "June 3 2022" +description: "Exploring how TypeScript infers types for iterators in for...in loops" +meta: for loops, maps, objects, sets, strings +--- + +# Why for...in and Object.keys() Give String Types + +Why does TypeScript report a `string` type instead of `keyof typeof` the object when you use a `for...in` loop or `Object.keys()` on an object? + +One of the most commonly asked questions in TypeScript help forums is why code like the following gives an error under the [`noImplicitAny` compiler option](https://www.typescriptlang.org/tsconfig#noImplicitAny). + +```ts twoslash +// @errors: 7053 +// @lib: dom,es2021 +const counts = { + one: 1, + two: 2, +}; + +for (const i in counts) { + // ^? + console.log(counts[i]); +} +``` + +Shouldn't TypeScript know that `i` is type `"one" | "two"`, a.k.a. `keyof typeof counts`? +Why is it telling us that `i` is `string` and can't be used like `counts[i]`? + +The answer is logical -though often inconvenient- and requires understanding a key characteristic of TypeScript's type system. + + + +## Objects May Have More Properties Than They Appear + +TypeScript's type system is _structurally typed_: meaning any value that happens to satisfy a type is allowed to be used as a value of that type. +In other words, when you declare that a value is of a particular object type, you're telling TypeScript any object that just so happens to have those properties is allowed to be considered that type. + +As a result, when you write a `for...in` loop over the keys of an object, you often won't have a guarantee that the object's keys will only be from the type of the object. +Some other area of code might have provided an object with more properties that just so happens to match the structural type. + +Take a look at this completely type safe code snippet that passes an object to a function. +What types would you expect for `i` inside the function's `for` loop? + +```ts twoslash +// @lib: dom,es2021 +interface TwoCounts { + one: number; + two: number; +} + +function iterateOverCounts(counts: TwoCounts) { + for (const i in counts) { + console.log(i); + } +} + +const counts = { + one: 1, + two: 2, + three: 3, +}; + +iterateOverCounts(counts); +``` + +`i` at _runtime_ will be `"one"`, `"two"`, then `"three"`. +But there's no reasonable way for TypeScript's type system to know that. +It just knows that `counts` is type `TwoCounts`, which has keys `"one"` and `"two"`. + +Thus, if TypeScript tried to assume that `i` was `keyof typeof counts` then the type system could be insidiously wrong. +For example, your code might assume `i` is only ever `"one"` or `"two`", and use it in logic that would crash with any other value! + +See [Workarounds](#workarounds) below for how you can get around this behavior in `for...in` loops. + +:::tip +Wondering why the first code snippet couldn't narrow `counts` to a more precise type? +See also [Why Objects Aren't Narrowed Before Usage](/articles/objects-narrowed-before-usage). +::: + +### `Object.keys()` Too + +This same design quirk applies to `Object.keys()`: + +```ts twoslash +// @lib: dom,es2021 +const counts = { + one: 1, + two: 2, +}; + +Object.keys(counts); +// ^? +``` + +`Object.keys()` and `for...in` loops work almost the same way. +The main difference is that `Object.keys()` only looks at properties on the object itself, while `for...in` loops also look at properties on the object's `prototype` chain. + +See [Workarounds](#workarounds) below for how you can get around this behavior in `Object.keys()` as well. + +## Workarounds + +Before you try to work around the design of the type checker, please pause a moment and reflect. +The situations mentioned earlier in this post are real problems in JavaScript and TypeScript code that have caused countless bugs in software. + +**TypeScript is right to assume `string` types.** + +### `Object` APIs + +TypeScript's type checking is designed to work with how JavaScript data typically flows and changes through an application. +Needing to wrestle with the type checker is often a byproduct of application code going against safe JavaScript practices -- such as the aforementioned issues with `for...in` loops receiving unexpected key strings. +In many cases, it might be good to listen to TypeScript and consider refactoring your code to use a JavaScript API better suited to the task. + +If all your code needs to do is get all the values in an object, an `Object.values()` API exists that returns those as an array. +You can `for...of` loop over them instead: + +```ts twoslash +// @lib: dom,esnext + +const counts = { + one: 1, + two: 2, +}; + +for (const value of Object.values(counts)) { + // ^? +} +``` + +Alternately, if you do need keys, consider using the `Object.entries()` API instead. +It returns a `[string, T][]` where `T` is the type of values in an object: + +```ts twoslash +// @lib: dom,esnext + +const counts = { + one: 1, + two: 2, +}; + +for (const [key, value] of Object.entries(counts)) { + key; + // ^? + value; + // ^? +} +``` + +Both `Object.entries()` and `Object.values()` allow you to write clean, idiomatic JavaScript without having to grapple with the type checker. + +### `Map` + +Taking an even larger step back, why is the application code looping over an object's keys and values? +Is the object meant to be used as a general key-value store? + +If so: consider using the built-in `Map` data structure instead. +It's made specifically for key-value stores. + +You can `for...of` over a `Map`'s values using `Array.from`: + +```ts twoslash +// @lib: dom,esnext + +const counts = new Map([ + ["one", 1], + ["two", 2], +]); + +for (const [key, value] of Array.from(counts)) { + key; + // ^? + value; + // ^? +} +``` + +`Map`s have the added benefit over `{}` objects of allowing any object to be a key without stringifying them first (which objects do). + +### Type Assertions + +Still, there are times when a `for...in` loop or `Object.keys()` might likely be mostly safe to use for object keys. +If you are 100% absolutely completely sure that your use case won't crash from some bizarre type mismatch now or in the future, you can always use an `as` assertion to cast the loop variable to the right type. + +One assertion strategy is to use `keyof typeof` to get the keys (`keyof`) of the object's type (`typeof`): + +```ts twoslash +// @lib: dom,es2021 +const counts = { + one: 1, + two: 2, +}; + +for (const i in counts) { + console.log(counts[i as keyof typeof counts]); // Ok +} +``` + +Alternately, if the object you're looping over is of a previously declared type, you can use the `keyof` operator on that type to get back a string literal union of its keys: + +```ts twoslash +// @lib: dom,es2021 +interface Counts { + one: number; + two: number; +} + +const counts: Counts = { + one: 1, + two: 2, +}; + +for (const i in counts) { + const count = counts[i as keyof Counts]; // Ok + // ^? + console.log(count); +} +``` + +## Further Reading + +See [this comment from Anders Hejlsberg](https://github.com/microsoft/TypeScript/pull/12253#issuecomment-263132208) and its surrounding PR for more details to this blog post on why the TypeScript team opted to keep this safer behavior. + +The TypeScript team and community have been discussing a [pending issue for "Exact" types](https://github.com/microsoft/TypeScript/issues/12936). +Exact types wouldn't allow arbitrary extra keys, so `for...in` loops over them would give the more narrow key types. +The issue has been open since 2016, though, so don't get your hopes up 😉. diff --git a/src/content/articles/named-properties-and-index-signatures.mdx b/src/content/articles/named-properties-and-index-signatures.mdx new file mode 100644 index 0000000..5803463 --- /dev/null +++ b/src/content/articles/named-properties-and-index-signatures.mdx @@ -0,0 +1,148 @@ +--- +date: "August 07 2022" +description: "Why named properties must be assignable to index signatures in TypeScript object types." +meta: assignability, index signatures, objects, properties +--- + +# Named Properties and Index Signatures in TypeScript + +[Index signatures](https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures) are a TypeScript feature that allow object types to declare that any arbitrary property on a type will have a certain property. +They're useful when you have an object meant to allow any arbitrary property of any name. + +For example, this object shape allows any property of on a value of type `FruitCounts` to have a `number` value: + +```ts twoslash +interface FruitCounts { + [i: string]: number; +} + +const counts: FruitCounts = {}; + +counts.apple = 1; +counts.banana = 2; +``` + +One rarely-used feature of index signatures is that you can mix and match them with named properties: + +```ts twoslash +interface MoreFruitCounts { + [i: string]: number; + + myLeastFavoriteFruit: 0; +} + +const counts: MoreFruitCounts = { + myLeastFavoriteFruit: 0, +}; + +counts.apple; +// ^? + +counts.myLeastFavoriteFruit; +// ^? +``` + +But, there is one restriction: the types of those properties must be assignable to the index signature's type: + +```ts twoslash +// @errors: 2411 +interface FruitCountsWithUnknown { + [i: string]: number; + + unknownFruit: string; +} +``` + +Why is that? +In a word: _assignability_. + + + +## Property Lookups and Assignability + +When an object's type contains an index signature and a property is retrieved from the type, TypeScript needs to be able to assume that the retrieved property is that index signature's type. + +However, if some properties of the object aren't assignable to the index signature's type, then that assumption will be wrong. + +Suppose an interface was allowed to have a property with a mismatched type, and code later retrieved a property from that interface under a dynamic property name -- as with `counts[fruit]` here: + +```ts twoslash +interface FruitCountsWithUnknown { + [i: string]: number; + + // @ts-expect-error + unknownFruit: string; +} + +// @ts-expect-error +const counts: FruitCountsWithUnknown = { + apple: 0, + unknownFruit: "Gotcha!", +}; + +function retrieveFruitCount(fruit: string) { + return counts[fruit]; +} + +const appleCount = retrieveFruitCount("apple"); +// ^? + +const unknownFruitCount = retrieveFruitCount("unknownFruit"); +// ^? +``` + +TypeScript would have no way of knowing when the retrieved property might be the named property's type instead of the index signature's type. + +## Numeric Index Signature Assignability + +JavaScript objects coerce property names to strings. +When you look up a property under a name that's not a string it'll be retrieved under the equivalent string key: + +```ts twoslash +const idCounts = { + "123": 0, +} as const; + +const countUnderNumber = idCounts[123]; +// ^? + +const countUnderString = idCounts["123"]; +// ^? +``` + +As a result, TypeScript allows index signatures over `number`s in addition to `string`s. +But they also have the same restriction as named properties: if a `string` index signature is present, the `number` index signature's types must be assignable to it. + +```ts twoslash +// @errors: 2413 +interface FruitOrIdCounts { + [i: string]: number; + + [i: number]: string; +} +``` + +You can think of both `number` index signatures and named properties to be considered subsets of `string` index signature properties. +Both may have their own, more specific types -- as long as those types are assignable to the catch-all `string` index signature's type. + +```ts twoslash +interface PuttingThemAllTogether { + [i: string]: number; + + myLeastFavoriteFruit: 0; + + [i: number]: 0 | 1 | 2 | 3; +} +``` + +:::note Food for Thought +Still having trouble getting your index signatures to work in TypeScript? +Consider reading [Why for...in and Object.keys() Give String Types](./for-in-string-types): you might be better off using a `Map` or `Set` +::: + +--- + +Index signatures are covered in _Learning TypeScript_'s Chapter 7: Interfaces. + +Got your own TypeScript questions? +Tweet [@LearningTSbook](https://twitter.com/LearningTSBook) and the answer might become an article too! diff --git a/src/content/articles/objects-narrowed-before-usage.mdx b/src/content/articles/objects-narrowed-before-usage.mdx new file mode 100644 index 0000000..bd6bddf --- /dev/null +++ b/src/content/articles/objects-narrowed-before-usage.mdx @@ -0,0 +1,61 @@ +--- +date: "June 1 2022" +description: "yippee!..." +meta: objects, narrowing, variables +--- + +# Why Objects Aren't Narrowed Before Usage + +```ts twoslash +const counts = { + one: 1, + two: 2, +}; + +const twoValue = counts.two; +// ^? +``` + +Shouldn't TypeScript know that `counts.two` is specifically the literal type `2` and not the general primitive type `number`? +Can't it tell we haven't changed the object yet. + +It can't, but it won't. +And for very good reason. + + + +## Change Tracking is Impractical + +The problem is that it's difficult -oftentimes impossible- for TypeScript to know whether an object has been modified if anything has happened between its initialization and first usage. +If the object is used in any meaningful application logic, TypeScript won't be able to tell whether it was modified. + +### A Practical Example + +Let's say you want to `console.log` the `counts` object before usage. +Your use your own custom `log` function that just so happens to only call `console.log`? +You'd still want `counts.two` to be `2`, right? + +```ts +function log(data: unknown) { + console.log(data); +} + +const counts = { + one: 1, + two: 2, +}; + +log(counts); + +const twoValue = counts.two; +// ^? +``` + +In theory, the `log` function could use the `readonly` modifier on its `data` parameter to indicate that +But many built-in user type definitions don't properly mark parameters as read-only. +Even `console.log` isn' marked as read-only as of TypeScript 4.7.2. + +## Further Reading + +A legendary [Trade-offs in Control Flow Analysis](https://github.com/microsoft/TypeScript/issues/9998) issue exists in the TypeScript repository. +It describes many more common trade-offs in how the TypeScript type checker analyzes the flow of values. diff --git a/src/css/custom.css b/src/css/custom.css index 3a3eaf5..3ed2cd6 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -20,17 +20,6 @@ --ifm-background-deemphasized-color: #222024; } -.docusaurus-highlight-code-line { - background-color: rgba(0, 0, 0, 0.1); - display: block; - margin: 0 calc(-1 * var(--ifm-pre-padding)); - padding: 0 var(--ifm-pre-padding); -} - -[data-theme="dark"] .docusaurus-highlight-code-line { - background-color: rgba(0, 0, 0, 0.3); -} - /* Header */ .navbar__items { @@ -75,6 +64,26 @@ margin-left: 0.75rem; } +/* Code & Twoslash */ + +[data-theme="dark"] .shiki.min-light { + display: none; +} + +[data-theme="light"] .shiki.nord { + display: none; +} + +/* Override for inaccessible (barely visible) light mode comments */ +.shiki.min-light span[style="color: rgb(194, 195, 197);"] { + color: #576 !important; +} + +/* Override for inaccessible (barely visible) dark mode comments */ +.shiki.nord span[style="color: rgb(97, 110, 136);"] { + color: #8a9 !important; +} + /* Bodies */ article .markdown a { diff --git a/yarn.lock b/yarn.lock index a9e1f66..6213f6a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2150,6 +2150,29 @@ dependencies: "@types/node" "*" +"@typescript/twoslash@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@typescript/twoslash/-/twoslash-3.1.0.tgz#20b4d4bb58729681ff7f4b187af98757ea8723d4" + integrity sha512-kTwMUQ8xtAZaC4wb2XuLkPqFVBj2dNBueMQ89NWEuw87k2nLBbuafeG5cob/QEr6YduxIdTVUjix0MtC7mPlmg== + dependencies: + "@typescript/vfs" "1.3.5" + debug "^4.1.1" + lz-string "^1.4.4" + +"@typescript/vfs@1.3.4": + version "1.3.4" + resolved "https://registry.yarnpkg.com/@typescript/vfs/-/vfs-1.3.4.tgz#07f89d2114f6e29255d589395ed7f3b4af8a00c2" + integrity sha512-RbyJiaAGQPIcAGWFa3jAXSuAexU4BFiDRF1g3hy7LmRqfNpYlTQWGXjcrOaVZjJ8YkkpuwG0FcsYvtWQpd9igQ== + dependencies: + debug "^4.1.1" + +"@typescript/vfs@1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@typescript/vfs/-/vfs-1.3.5.tgz#801e3c97b5beca4ff5b8763299ca5fd605b862b8" + integrity sha512-pI8Saqjupf9MfLw7w2+og+fmb0fZS0J6vsKXXrp4/PDXEFvntgzXmChCXC/KefZZS0YGS6AT8e0hGAJcTsdJlg== + dependencies: + debug "^4.1.1" + "@webassemblyjs/ast@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" @@ -3451,6 +3474,15 @@ dns-packet@^5.2.2: dependencies: "@leichtgewicht/ip-codec" "^2.0.1" +docusaurus-preset-shiki-twoslash@^1.1.38: + version "1.1.38" + resolved "https://registry.yarnpkg.com/docusaurus-preset-shiki-twoslash/-/docusaurus-preset-shiki-twoslash-1.1.38.tgz#297ddff7b5b84bc6bc9ebf32a3ee1ff17ae0e035" + integrity sha512-v8bp6Q6gUNLuWmf4x19Tk2VvjEc8Luuy6o7fpTg7fTFUwo7ZBVWPTrxJe/aN4OmjkVBmuDfBc/muUGEAJTVm2g== + dependencies: + copy-text-to-clipboard "^3.0.1" + remark-shiki-twoslash "3.1.0" + typescript ">3" + dom-converter@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" @@ -3899,6 +3931,11 @@ feed@^4.2.2: dependencies: xml-js "^1.6.11" +fenceparser@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fenceparser/-/fenceparser-1.1.1.tgz#e10a5f12a54884d4f14edb0f7a52a0edc58fa667" + integrity sha512-VdkTsK7GWLT0VWMK5S5WTAPn61wJ98WPFwJiRHumhg4ESNUO/tnkU8bzzzc62o6Uk1SVhuZFLnakmDA4SGV7wA== + file-loader@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" @@ -4898,6 +4935,11 @@ json5@^2.1.2, json5@^2.2.1: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== +jsonc-parser@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.1.0.tgz#73b8f0e5c940b83d03476bc2e51a20ef0932615d" + integrity sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg== + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -5131,6 +5173,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lz-string@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" + integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ== + make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -6595,7 +6642,7 @@ regenerate@^1.4.2: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@^0.13.4: +regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: version "0.13.9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== @@ -6718,6 +6765,21 @@ remark-parse@8.0.3: vfile-location "^3.0.0" xtend "^4.0.1" +remark-shiki-twoslash@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/remark-shiki-twoslash/-/remark-shiki-twoslash-3.1.0.tgz#b5e58eec9f97458ade1df73cb96566d031cc75bd" + integrity sha512-6LqSqVtHQR4S0DKfdQ2/ePn9loTKUtpyopYvwk8johjDTeUW5MkaLQuZHlWNkkST/4aMbz6aTkstIcwfwcHpXg== + dependencies: + "@typescript/twoslash" "3.1.0" + "@typescript/vfs" "1.3.4" + fenceparser "^1.1.0" + regenerator-runtime "^0.13.7" + shiki "0.10.1" + shiki-twoslash "3.1.0" + tslib "2.1.0" + typescript ">3" + unist-util-visit "^2.0.0" + remark-squeeze-paragraphs@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz#76eb0e085295131c84748c8e43810159c5653ead" @@ -7065,6 +7127,25 @@ shelljs@^0.8.5: interpret "^1.0.0" rechoir "^0.6.2" +shiki-twoslash@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/shiki-twoslash/-/shiki-twoslash-3.1.0.tgz#818aaa15e83e0f34325dd56a991f7023f7e8e6db" + integrity sha512-uDqrTutOIZzyHbo103GsK7Vvc10saK1XCCivnOQ1NHJzgp3FBilEpftGeVzVSMOJs+JyhI7whkvhXV7kXQ5zCg== + dependencies: + "@typescript/twoslash" "3.1.0" + "@typescript/vfs" "1.3.4" + shiki "0.10.1" + typescript ">3" + +shiki@0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.10.1.tgz#6f9a16205a823b56c072d0f1a0bcd0f2646bef14" + integrity sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng== + dependencies: + jsonc-parser "^3.0.0" + vscode-oniguruma "^1.6.1" + vscode-textmate "5.2.0" + signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" @@ -7436,6 +7517,11 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== +tslib@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" + integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== + tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" @@ -7466,6 +7552,11 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typescript@>3: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + typescript@^4.6.3: version "4.6.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" @@ -7740,6 +7831,16 @@ vfile@^4.0.0: unist-util-stringify-position "^2.0.0" vfile-message "^2.0.0" +vscode-oniguruma@^1.6.1: + version "1.6.2" + resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz#aeb9771a2f1dbfc9083c8a7fdd9cccaa3f386607" + integrity sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA== + +vscode-textmate@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" + integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== + wait-on@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-6.0.1.tgz#16bbc4d1e4ebdd41c5b4e63a2e16dbd1f4e5601e"