diff --git a/changelog_unreleased/typescript/13764.md b/changelog_unreleased/typescript/13764.md new file mode 100644 index 000000000000..43f84930a7ae --- /dev/null +++ b/changelog_unreleased/typescript/13764.md @@ -0,0 +1,16 @@ +#### Support TypeScript 4.9 (#13764 by @sosukesuzuki) + +Support [TypeScript 4.9](https://devblogs.microsoft.com/typescript/announcing-typescript-4-9) features! + +##### [`satisfies` operator](https://devblogs.microsoft.com/typescript/announcing-typescript-4-9-beta/#the-satisfies-operator) + +Supported by only `babel-ts` parser. + + +```tsx +const palette = { + red: [255, 0, 0], + green: "#00ff00", + blue: [0, 0, 255] +} satisfies Record; +``` diff --git a/src/language-js/needs-parens.js b/src/language-js/needs-parens.js index 54da4fefeca9..20d2e0f789ea 100644 --- a/src/language-js/needs-parens.js +++ b/src/language-js/needs-parens.js @@ -11,6 +11,7 @@ import { isCallExpression, isMemberExpression, isObjectProperty, + isTSTypeExpression, } from "./utils/index.js"; function needsParens(path, options) { @@ -227,14 +228,20 @@ function needsParens(path, options) { // fallthrough case "TSTypeAssertion": case "TSAsExpression": + case "TSSatisfiesExpression": case "LogicalExpression": switch (parent.type) { case "TSAsExpression": - // example: foo as unknown as Bar - return node.type !== "TSAsExpression"; + case "TSSatisfiesExpression": + // examples: + // foo as unknown as Bar + // foo satisfies unknown satisfies Bar + // foo satisfies unknown as Bar + // foo as unknown satisfies Bar + return !isTSTypeExpression(node); case "ConditionalExpression": - return node.type === "TSAsExpression"; + return isTSTypeExpression(node); case "CallExpression": case "NewExpression": @@ -265,7 +272,11 @@ function needsParens(path, options) { case "AssignmentPattern": return ( key === "left" && - (node.type === "TSTypeAssertion" || node.type === "TSAsExpression") + (node.type === "TSTypeAssertion" || + // babel-parser cannot parse `satisfies` operator in left side of assignment + // https://github.com/babel/babel/issues/15095 + // TODO: Add tests after the bug is fixed + isTSTypeExpression(node)) ); case "LogicalExpression": @@ -360,6 +371,7 @@ function needsParens(path, options) { case "SpreadElement": case "SpreadProperty": case "TSAsExpression": + case "TSSatisfiesExpression": case "TSNonNullExpression": case "BindExpression": return true; @@ -592,6 +604,7 @@ function needsParens(path, options) { case "TSTypeAssertion": case "TypeCastExpression": case "TSAsExpression": + case "TSSatisfiesExpression": case "TSNonNullExpression": return true; @@ -641,6 +654,7 @@ function needsParens(path, options) { return key === "object"; case "TSAsExpression": + case "TSSatisfiesExpression": case "TSNonNullExpression": case "BindExpression": case "TaggedTemplateExpression": diff --git a/src/language-js/print/call-arguments.js b/src/language-js/print/call-arguments.js index ed414843eca4..f4a0a37bb052 100644 --- a/src/language-js/print/call-arguments.js +++ b/src/language-js/print/call-arguments.js @@ -19,6 +19,7 @@ import { isRegExpLiteral, isSimpleType, isCallLikeExpression, + isTSTypeExpression, } from "../utils/index.js"; import { @@ -186,7 +187,7 @@ function couldExpandArg(arg, arrowChainRecursion = false) { (arg.type === "ArrayExpression" && (arg.elements.length > 0 || hasComment(arg))) || (arg.type === "TSTypeAssertion" && couldExpandArg(arg.expression)) || - (arg.type === "TSAsExpression" && couldExpandArg(arg.expression)) || + (isTSTypeExpression(arg) && couldExpandArg(arg.expression)) || arg.type === "FunctionExpression" || (arg.type === "ArrowFunctionExpression" && // we want to avoid breaking inside composite return types but not simple keywords @@ -286,7 +287,7 @@ function isHopefullyShortCallArgument(node) { return isHopefullyShortCallArgument(node.expression); } - if (node.type === "TSAsExpression") { + if (isTSTypeExpression(node)) { let { typeAnnotation } = node; if (typeAnnotation.type === "TSArrayType") { typeAnnotation = typeAnnotation.elementType; diff --git a/src/language-js/print/template-literal.js b/src/language-js/print/template-literal.js index 19308711636e..178d93c13b58 100644 --- a/src/language-js/print/template-literal.js +++ b/src/language-js/print/template-literal.js @@ -17,6 +17,7 @@ import { isSimpleTemplateLiteral, hasComment, isMemberExpression, + isTSTypeExpression, } from "../utils/index.js"; function printTemplateLiteral(path, print, options) { @@ -87,7 +88,7 @@ function printTemplateLiteral(path, print, options) { isMemberExpression(expression) || expression.type === "ConditionalExpression" || expression.type === "SequenceExpression" || - expression.type === "TSAsExpression" || + isTSTypeExpression(expression) || isBinaryish(expression) ) { expressionDoc = [indent([softline, expressionDoc]), softline]; diff --git a/src/language-js/print/ternary.js b/src/language-js/print/ternary.js index 310ab3a7d08f..471670c6e59e 100644 --- a/src/language-js/print/ternary.js +++ b/src/language-js/print/ternary.js @@ -4,6 +4,7 @@ import { getComments, isCallExpression, isMemberExpression, + isTSTypeExpression, } from "../utils/index.js"; import { locStart, locEnd } from "../loc.js"; import isBlockComment from "../utils/is-block-comment.js"; @@ -161,7 +162,7 @@ function shouldExtraIndentForConditionalExpression(path) { if ( (node.type === "NewExpression" && node.callee === child) || - (node.type === "TSAsExpression" && node.expression === child) + (isTSTypeExpression(node) && node.expression === child) ) { parent = path.getParentNode(ancestorCount + 1); child = node; diff --git a/src/language-js/print/typescript.js b/src/language-js/print/typescript.js index de52a01100f4..36af1c8f0626 100644 --- a/src/language-js/print/typescript.js +++ b/src/language-js/print/typescript.js @@ -142,8 +142,10 @@ function printTypescript(path, options, print) { return printTypeParameters(path, options, print, "params"); case "TSTypeParameter": return printTypeParameter(path, options, print); - case "TSAsExpression": { - parts.push(print("expression"), " as ", print("typeAnnotation")); + case "TSAsExpression": + case "TSSatisfiesExpression": { + const operator = node.type === "TSAsExpression" ? "as" : "satisfies"; + parts.push(print("expression"), ` ${operator} `, print("typeAnnotation")); const { parent } = path; if ( (isCallExpression(parent) && parent.callee === node) || diff --git a/src/language-js/utils/index.js b/src/language-js/utils/index.js index d786ec96566d..0460c0ae9a57 100644 --- a/src/language-js/utils/index.js +++ b/src/language-js/utils/index.js @@ -62,7 +62,7 @@ function hasNakedLeftSide(node) { node.type === "TaggedTemplateExpression" || node.type === "BindExpression" || (node.type === "UpdateExpression" && !node.prefix) || - node.type === "TSAsExpression" || + isTSTypeExpression(node) || node.type === "TSNonNullExpression" ); } @@ -898,6 +898,7 @@ function startsWithNoLookaheadToken(node, forbidFunctionClassAndDoExpr) { forbidFunctionClassAndDoExpr ); case "TSAsExpression": + case "TSSatisfiesExpression": case "TSNonNullExpression": return startsWithNoLookaheadToken( node.expression, @@ -1219,6 +1220,12 @@ const markerForIfWithoutBlockAndSameLineComment = Symbol( "ifWithoutBlockAndSameLineComment" ); +function isTSTypeExpression(node) { + return ( + node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression" + ); +} + export { getFunctionParameters, iterateFunctionParametersPath, @@ -1280,4 +1287,5 @@ export { getComments, CommentCheckFlags, markerForIfWithoutBlockAndSameLineComment, + isTSTypeExpression, }; diff --git a/tests/config/format-test.js b/tests/config/format-test.js index cfd11bae8a0b..51c51d695e66 100644 --- a/tests/config/format-test.js +++ b/tests/config/format-test.js @@ -37,6 +37,7 @@ const unstableTests = new Map( "typescript/prettier-ignore/mapped-types.ts", "js/comments/html-like/comment.js", "js/for/continue-and-break-comment-without-blocks.js", + "typescript/satisfies-operators/comments-unstable.ts", ].map((fixture) => { const [file, isUnstable = () => true] = Array.isArray(fixture) ? fixture diff --git a/tests/format/typescript/argument-expansion/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/argument-expansion/__snapshots__/jsfmt.spec.js.snap index b7d32acbf480..8a462ba4840a 100644 --- a/tests/format/typescript/argument-expansion/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/argument-expansion/__snapshots__/jsfmt.spec.js.snap @@ -38,6 +38,10 @@ const bar8 = [1,2,3].reduce((carry, value) => { return {...carry, [value]: true}; }, <{[key: number]: boolean}>{1: true}); +const bar9 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, [] as foo); + =====================================output===================================== const bar1 = [1, 2, 3].reduce( (carry, value) => { @@ -95,6 +99,10 @@ const bar8 = [1, 2, 3].reduce( <{ [key: number]: boolean }>{ 1: true }, ); +const bar9 = [1, 2, 3].reduce((carry, value) => { + return [...carry, value]; +}, [] as foo); + ================================================================================ `; diff --git a/tests/format/typescript/argument-expansion/argument_expansion.ts b/tests/format/typescript/argument-expansion/argument_expansion.ts index 37f77d346e1b..9230cac27569 100644 --- a/tests/format/typescript/argument-expansion/argument_expansion.ts +++ b/tests/format/typescript/argument-expansion/argument_expansion.ts @@ -29,3 +29,7 @@ const bar7 = [1,2,3].reduce((carry, value) => { const bar8 = [1,2,3].reduce((carry, value) => { return {...carry, [value]: true}; }, <{[key: number]: boolean}>{1: true}); + +const bar9 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, [] as foo); diff --git a/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2a4c951f3588 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,1087 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`argument-expansion.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const bar1 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([] satisfies unknown) satisfies number[]); + +const bar2 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([1, 2, 3] satisfies unknown) satisfies number[]); + +const bar3 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar4 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({1: true} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar5 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, [] satisfies foo); + +=====================================output===================================== +const bar1 = [1, 2, 3].reduce( + (carry, value) => { + return [...carry, value] + }, + [] satisfies unknown satisfies number[], +) + +const bar2 = [1, 2, 3].reduce( + (carry, value) => { + return [...carry, value] + }, + [1, 2, 3] satisfies unknown satisfies number[], +) + +const bar3 = [1, 2, 3].reduce( + (carry, value) => { + return { ...carry, [value]: true } + }, + {} satisfies unknown satisfies { [key: number]: boolean }, +) + +const bar4 = [1, 2, 3].reduce( + (carry, value) => { + return { ...carry, [value]: true } + }, + { 1: true } satisfies unknown satisfies { [key: number]: boolean }, +) + +const bar5 = [1, 2, 3].reduce((carry, value) => { + return [...carry, value] +}, [] satisfies foo) + +================================================================================ +`; + +exports[`argument-expansion.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const bar1 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([] satisfies unknown) satisfies number[]); + +const bar2 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([1, 2, 3] satisfies unknown) satisfies number[]); + +const bar3 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar4 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({1: true} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar5 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, [] satisfies foo); + +=====================================output===================================== +const bar1 = [1, 2, 3].reduce( + (carry, value) => { + return [...carry, value]; + }, + [] satisfies unknown satisfies number[], +); + +const bar2 = [1, 2, 3].reduce( + (carry, value) => { + return [...carry, value]; + }, + [1, 2, 3] satisfies unknown satisfies number[], +); + +const bar3 = [1, 2, 3].reduce( + (carry, value) => { + return { ...carry, [value]: true }; + }, + {} satisfies unknown satisfies { [key: number]: boolean }, +); + +const bar4 = [1, 2, 3].reduce( + (carry, value) => { + return { ...carry, [value]: true }; + }, + { 1: true } satisfies unknown satisfies { [key: number]: boolean }, +); + +const bar5 = [1, 2, 3].reduce((carry, value) => { + return [...carry, value]; +}, [] satisfies foo); + +================================================================================ +`; + +exports[`assignment.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const extraRendererAttrs = ((attrs.rendererAttrs && + this.utils.safeParseJsonString(attrs.rendererAttrs)) || + Object.create(null)) satisfies FieldService.RendererAttributes; + +const annotate = (angular.injector satisfies any).$$annotate satisfies ( + fn: Function +) => string[]; + +const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, + propertyToServiceName = originalPrototype._inject; + +this.previewPlayerHandle = (setInterval(async () => { + if (this.previewIsPlaying) { + await this.fetchNextPreviews(); + this.currentPreviewIndex++; + } +}, this.refreshDelay) satisfies unknown) satisfies number; + +this.intervalID = (setInterval(() => { + self.step(); +}, 30) satisfies unknown) satisfies number; + +=====================================output===================================== +const extraRendererAttrs = ((attrs.rendererAttrs && + this.utils.safeParseJsonString(attrs.rendererAttrs)) || + Object.create(null)) satisfies FieldService.RendererAttributes + +const annotate = (angular.injector satisfies any).$$annotate satisfies ( + fn: Function, +) => string[] + +const originalPrototype = originalConstructor.prototype satisfies TComponent & + InjectionTarget, + propertyToServiceName = originalPrototype._inject + +this.previewPlayerHandle = setInterval(async () => { + if (this.previewIsPlaying) { + await this.fetchNextPreviews() + this.currentPreviewIndex++ + } +}, this.refreshDelay) satisfies unknown satisfies number + +this.intervalID = setInterval(() => { + self.step() +}, 30) satisfies unknown satisfies number + +================================================================================ +`; + +exports[`assignment.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const extraRendererAttrs = ((attrs.rendererAttrs && + this.utils.safeParseJsonString(attrs.rendererAttrs)) || + Object.create(null)) satisfies FieldService.RendererAttributes; + +const annotate = (angular.injector satisfies any).$$annotate satisfies ( + fn: Function +) => string[]; + +const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, + propertyToServiceName = originalPrototype._inject; + +this.previewPlayerHandle = (setInterval(async () => { + if (this.previewIsPlaying) { + await this.fetchNextPreviews(); + this.currentPreviewIndex++; + } +}, this.refreshDelay) satisfies unknown) satisfies number; + +this.intervalID = (setInterval(() => { + self.step(); +}, 30) satisfies unknown) satisfies number; + +=====================================output===================================== +const extraRendererAttrs = ((attrs.rendererAttrs && + this.utils.safeParseJsonString(attrs.rendererAttrs)) || + Object.create(null)) satisfies FieldService.RendererAttributes; + +const annotate = (angular.injector satisfies any).$$annotate satisfies ( + fn: Function, +) => string[]; + +const originalPrototype = originalConstructor.prototype satisfies TComponent & + InjectionTarget, + propertyToServiceName = originalPrototype._inject; + +this.previewPlayerHandle = setInterval(async () => { + if (this.previewIsPlaying) { + await this.fetchNextPreviews(); + this.currentPreviewIndex++; + } +}, this.refreshDelay) satisfies unknown satisfies number; + +this.intervalID = setInterval(() => { + self.step(); +}, 30) satisfies unknown satisfies number; + +================================================================================ +`; + +exports[`basic.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const t1 = { a: 1 } satisfies I1; +const t2 = { a: 1, b: 1 } satisfies I1; +const t3 = { } satisfies I1; +const t4: T1 = { a: "a" } satisfies T1; +const t5 = (m => m.substring(0)) satisfies T2; +const t6 = [1, 2] satisfies [number, number]; +let t7 = { a: 'test' } satisfies A; +let t8 = { a: 'test', b: 'test' } satisfies A; + +const p = { + isEven: n => n % 2 === 0, + isOdd: n => n % 2 === 1 +} satisfies Predicates; + +let obj: { f(s: string): void } & Record = { + f(s) { }, + g(s) { } +} satisfies { g(s: string): void } & Record; + +({ f(x) { } }) satisfies { f(s: string): void }; + +const car = { + start() { }, + move(d) { + // d should be number + }, + stop() { } +} satisfies Movable & Record; + +var v = undefined satisfies 1; + +=====================================output===================================== +const t1 = { a: 1 } satisfies I1 +const t2 = { a: 1, b: 1 } satisfies I1 +const t3 = {} satisfies I1 +const t4: T1 = { a: "a" } satisfies T1 +const t5 = ((m) => m.substring(0)) satisfies T2 +const t6 = [1, 2] satisfies [number, number] +let t7 = { a: "test" } satisfies A +let t8 = { a: "test", b: "test" } satisfies A + +const p = { + isEven: (n) => n % 2 === 0, + isOdd: (n) => n % 2 === 1, +} satisfies Predicates + +let obj: { f(s: string): void } & Record = { + f(s) {}, + g(s) {}, +} satisfies { g(s: string): void } & Record + +;({ f(x) {} } satisfies { f(s: string): void }) + +const car = { + start() {}, + move(d) { + // d should be number + }, + stop() {}, +} satisfies Movable & Record + +var v = undefined satisfies 1 + +================================================================================ +`; + +exports[`basic.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const t1 = { a: 1 } satisfies I1; +const t2 = { a: 1, b: 1 } satisfies I1; +const t3 = { } satisfies I1; +const t4: T1 = { a: "a" } satisfies T1; +const t5 = (m => m.substring(0)) satisfies T2; +const t6 = [1, 2] satisfies [number, number]; +let t7 = { a: 'test' } satisfies A; +let t8 = { a: 'test', b: 'test' } satisfies A; + +const p = { + isEven: n => n % 2 === 0, + isOdd: n => n % 2 === 1 +} satisfies Predicates; + +let obj: { f(s: string): void } & Record = { + f(s) { }, + g(s) { } +} satisfies { g(s: string): void } & Record; + +({ f(x) { } }) satisfies { f(s: string): void }; + +const car = { + start() { }, + move(d) { + // d should be number + }, + stop() { } +} satisfies Movable & Record; + +var v = undefined satisfies 1; + +=====================================output===================================== +const t1 = { a: 1 } satisfies I1; +const t2 = { a: 1, b: 1 } satisfies I1; +const t3 = {} satisfies I1; +const t4: T1 = { a: "a" } satisfies T1; +const t5 = ((m) => m.substring(0)) satisfies T2; +const t6 = [1, 2] satisfies [number, number]; +let t7 = { a: "test" } satisfies A; +let t8 = { a: "test", b: "test" } satisfies A; + +const p = { + isEven: (n) => n % 2 === 0, + isOdd: (n) => n % 2 === 1, +} satisfies Predicates; + +let obj: { f(s: string): void } & Record = { + f(s) {}, + g(s) {}, +} satisfies { g(s: string): void } & Record; + +({ f(x) {} } satisfies { f(s: string): void }); + +const car = { + start() {}, + move(d) { + // d should be number + }, + stop() {}, +} satisfies Movable & Record; + +var v = undefined satisfies 1; + +================================================================================ +`; + +exports[`comments.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; + +=====================================output===================================== +const t2 = {} /* comment */ satisfies {} +const t3 = {} satisfies /* comment */ {} +const t4 = {} /* comment1 */ satisfies /* comment2 */ {} + +================================================================================ +`; + +exports[`comments.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; + +=====================================output===================================== +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; + +================================================================================ +`; + +exports[`comments-unstable.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3 +} satisfies +// Comment +Record; + +=====================================output===================================== +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3, +} satisfies // Comment +Record + +================================================================================ +`; + +exports[`comments-unstable.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3 +} satisfies +// Comment +Record; + +=====================================output===================================== +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3, +} satisfies // Comment +Record; + +================================================================================ +`; + +exports[`export-default-as.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +export default (function log() {} satisfies typeof console.log) + +=====================================output===================================== +export default (function log() {} satisfies typeof console.log) + +================================================================================ +`; + +exports[`export-default-as.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +export default (function log() {} satisfies typeof console.log) + +=====================================output===================================== +export default (function log() {} satisfies typeof console.log); + +================================================================================ +`; + +exports[`gt-lt.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +x satisfies boolean <= y; // (x satisfies boolean) <= y; +x satisfies boolean ?? y; // (x satisfies boolean) ?? y; + +=====================================output===================================== +;(x satisfies boolean) <= y // (x satisfies boolean) <= y; +;(x satisfies boolean) ?? y // (x satisfies boolean) ?? y; + +================================================================================ +`; + +exports[`gt-lt.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +x satisfies boolean <= y; // (x satisfies boolean) <= y; +x satisfies boolean ?? y; // (x satisfies boolean) ?? y; + +=====================================output===================================== +(x satisfies boolean) <= y; // (x satisfies boolean) <= y; +(x satisfies boolean) ?? y; // (x satisfies boolean) ?? y; + +================================================================================ +`; + +exports[`hug-args.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +window.postMessage( + { + context: item.context, + topic: item.topic + } satisfies IActionMessage + ); + +=====================================output===================================== +window.postMessage({ + context: item.context, + topic: item.topic, +} satisfies IActionMessage) + +================================================================================ +`; + +exports[`hug-args.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +window.postMessage( + { + context: item.context, + topic: item.topic + } satisfies IActionMessage + ); + +=====================================output===================================== +window.postMessage({ + context: item.context, + topic: item.topic, +} satisfies IActionMessage); + +================================================================================ +`; + +exports[`nested-await-and-satisfies.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const getAccountCount = async () => + (await + ((await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem + ).getChildren() + ).length + +=====================================output===================================== +const getAccountCount = async () => + ( + await ( + (await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem + ).getChildren() + ).length + +================================================================================ +`; + +exports[`nested-await-and-satisfies.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const getAccountCount = async () => + (await + ((await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem + ).getChildren() + ).length + +=====================================output===================================== +const getAccountCount = async () => + ( + await ( + (await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem + ).getChildren() + ).length; + +================================================================================ +`; + +exports[`non-null.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +// the 2nd line needs ASI protection +const el = ReactDOM.findDOMNode(ref) +;(el satisfies HTMLElement)!.style.cursor = 'pointer' + +=====================================output===================================== +// the 2nd line needs ASI protection +const el = ReactDOM.findDOMNode(ref) +;(el satisfies HTMLElement)!.style.cursor = "pointer" + +================================================================================ +`; + +exports[`non-null.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +// the 2nd line needs ASI protection +const el = ReactDOM.findDOMNode(ref) +;(el satisfies HTMLElement)!.style.cursor = 'pointer' + +=====================================output===================================== +// the 2nd line needs ASI protection +const el = ReactDOM.findDOMNode(ref); +(el satisfies HTMLElement)!.style.cursor = "pointer"; + +================================================================================ +`; + +exports[`satisfies.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +({}) satisfies {}; +({}) satisfies X; +() => ({}) satisfies X; +this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement); + +'current' in (props.pagination satisfies Object); +('current' in props.pagination) satisfies Object; +start + (yearSelectTotal satisfies number); +(start + yearSelectTotal) satisfies number; +scrollTop > (visibilityHeight satisfies number); +(scrollTop > visibilityHeight) satisfies number; +(bValue satisfies boolean) ? 0 : -1; + +async function g1() { + const test = (await 'foo') satisfies number; +} + +var x = (v => v) satisfies (x: number) => string; + +foo satisfies unknown satisfies Bar; +foo satisfies unknown as Bar; +foo as unknown satisfies Bar; + +=====================================output===================================== +;({} satisfies {}) +;({} satisfies X) +;() => ({} satisfies X) +this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement) + +"current" in (props.pagination satisfies Object) +;("current" in props.pagination) satisfies Object +start + (yearSelectTotal satisfies number) +;(start + yearSelectTotal) satisfies number +scrollTop > (visibilityHeight satisfies number) +;(scrollTop > visibilityHeight) satisfies number +;(bValue satisfies boolean) ? 0 : -1 + +async function g1() { + const test = (await "foo") satisfies number +} + +var x = ((v) => v) satisfies (x: number) => string + +foo satisfies unknown satisfies Bar +foo satisfies unknown as Bar +foo as unknown satisfies Bar + +================================================================================ +`; + +exports[`satisfies.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +({}) satisfies {}; +({}) satisfies X; +() => ({}) satisfies X; +this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement); + +'current' in (props.pagination satisfies Object); +('current' in props.pagination) satisfies Object; +start + (yearSelectTotal satisfies number); +(start + yearSelectTotal) satisfies number; +scrollTop > (visibilityHeight satisfies number); +(scrollTop > visibilityHeight) satisfies number; +(bValue satisfies boolean) ? 0 : -1; + +async function g1() { + const test = (await 'foo') satisfies number; +} + +var x = (v => v) satisfies (x: number) => string; + +foo satisfies unknown satisfies Bar; +foo satisfies unknown as Bar; +foo as unknown satisfies Bar; + +=====================================output===================================== +({} satisfies {}); +({} satisfies X); +() => ({} satisfies X); +this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement); + +"current" in (props.pagination satisfies Object); +("current" in props.pagination) satisfies Object; +start + (yearSelectTotal satisfies number); +(start + yearSelectTotal) satisfies number; +scrollTop > (visibilityHeight satisfies number); +(scrollTop > visibilityHeight) satisfies number; +(bValue satisfies boolean) ? 0 : -1; + +async function g1() { + const test = (await "foo") satisfies number; +} + +var x = ((v) => v) satisfies (x: number) => string; + +foo satisfies unknown satisfies Bar; +foo satisfies unknown as Bar; +foo as unknown satisfies Bar; + +================================================================================ +`; + +exports[`template-literal.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +const a = \`\${(foo + bar) satisfies baz}\`; +const b = \`\${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar) satisfies baz}\`; +const b = \`\${(foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies baz}\`; +const b = \`\${(foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}\`; +const b = \`\${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}\`; + +=====================================output===================================== +const a = \`\${(foo + bar) satisfies baz}\` +const b = \`\${ + (veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar) satisfies baz +}\` +const b = \`\${ + (foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies baz +}\` +const b = \`\${ + (foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz +}\` +const b = \`\${ + (veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz +}\` + +================================================================================ +`; + +exports[`template-literal.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +const a = \`\${(foo + bar) satisfies baz}\`; +const b = \`\${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar) satisfies baz}\`; +const b = \`\${(foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies baz}\`; +const b = \`\${(foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}\`; +const b = \`\${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}\`; + +=====================================output===================================== +const a = \`\${(foo + bar) satisfies baz}\`; +const b = \`\${ + (veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar) satisfies baz +}\`; +const b = \`\${ + (foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies baz +}\`; +const b = \`\${ + (foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz +}\`; +const b = \`\${ + (veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz +}\`; + +================================================================================ +`; + +exports[`ternary.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +foo = (condition ? firstValue : secondValue) satisfies SomeType; + +const foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +function foo() { + return (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + throw (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + void ((coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo); +} + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 && + kochabCooieGameOnOboleUnweave === Math.PI + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +=====================================output===================================== +foo = ( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz +) satisfies Fooooooooooo + +foo = (condition ? firstValue : secondValue) satisfies SomeType + +const foo = ( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz +) satisfies Fooooooooooo + +function foo() { + return ( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + ) satisfies Fooooooooooo +} + +function foo() { + throw ( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + ) satisfies Fooooooooooo +} + +function foo() { + void (( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + ) satisfies Fooooooooooo) +} + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay) + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 && + kochabCooieGameOnOboleUnweave === Math.PI + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay) + +================================================================================ +`; + +exports[`ternary.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +foo = (condition ? firstValue : secondValue) satisfies SomeType; + +const foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +function foo() { + return (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + throw (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + void ((coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo); +} + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 && + kochabCooieGameOnOboleUnweave === Math.PI + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +=====================================output===================================== +foo = ( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz +) satisfies Fooooooooooo; + +foo = (condition ? firstValue : secondValue) satisfies SomeType; + +const foo = ( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz +) satisfies Fooooooooooo; + +function foo() { + return ( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + ) satisfies Fooooooooooo; +} + +function foo() { + throw ( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + ) satisfies Fooooooooooo; +} + +function foo() { + void (( + coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz + ) satisfies Fooooooooooo); +} + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 && + kochabCooieGameOnOboleUnweave === Math.PI + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +================================================================================ +`; + +exports[`types-comments.ts - {"semi":false} format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 +semi: false + | printWidth +=====================================input====================================== +(() => { + // swallow error and fallback to using directory as path +}) satisfies string[]; + +=====================================output===================================== +;(() => { + // swallow error and fallback to using directory as path +}) satisfies string[] + +================================================================================ +`; + +exports[`types-comments.ts format 1`] = ` +====================================options===================================== +parsers: ["babel-ts"] +printWidth: 80 + | printWidth +=====================================input====================================== +(() => { + // swallow error and fallback to using directory as path +}) satisfies string[]; + +=====================================output===================================== +(() => { + // swallow error and fallback to using directory as path +}) satisfies string[]; + +================================================================================ +`; diff --git a/tests/format/typescript/satisfies-operators/argument-expansion.ts b/tests/format/typescript/satisfies-operators/argument-expansion.ts new file mode 100644 index 000000000000..aef1a1410c1a --- /dev/null +++ b/tests/format/typescript/satisfies-operators/argument-expansion.ts @@ -0,0 +1,19 @@ +const bar1 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([] satisfies unknown) satisfies number[]); + +const bar2 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, ([1, 2, 3] satisfies unknown) satisfies number[]); + +const bar3 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar4 = [1,2,3].reduce((carry, value) => { + return {...carry, [value]: true}; +}, ({1: true} satisfies unknown) satisfies {[key: number]: boolean}); + +const bar5 = [1,2,3].reduce((carry, value) => { + return [...carry, value]; +}, [] satisfies foo); diff --git a/tests/format/typescript/satisfies-operators/assignment.ts b/tests/format/typescript/satisfies-operators/assignment.ts new file mode 100644 index 000000000000..9b7139253bc4 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/assignment.ts @@ -0,0 +1,21 @@ +const extraRendererAttrs = ((attrs.rendererAttrs && + this.utils.safeParseJsonString(attrs.rendererAttrs)) || + Object.create(null)) satisfies FieldService.RendererAttributes; + +const annotate = (angular.injector satisfies any).$$annotate satisfies ( + fn: Function +) => string[]; + +const originalPrototype = originalConstructor.prototype satisfies TComponent & InjectionTarget, + propertyToServiceName = originalPrototype._inject; + +this.previewPlayerHandle = (setInterval(async () => { + if (this.previewIsPlaying) { + await this.fetchNextPreviews(); + this.currentPreviewIndex++; + } +}, this.refreshDelay) satisfies unknown) satisfies number; + +this.intervalID = (setInterval(() => { + self.step(); +}, 30) satisfies unknown) satisfies number; diff --git a/tests/format/typescript/satisfies-operators/basic.ts b/tests/format/typescript/satisfies-operators/basic.ts new file mode 100644 index 000000000000..3eff7182b432 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/basic.ts @@ -0,0 +1,30 @@ +const t1 = { a: 1 } satisfies I1; +const t2 = { a: 1, b: 1 } satisfies I1; +const t3 = { } satisfies I1; +const t4: T1 = { a: "a" } satisfies T1; +const t5 = (m => m.substring(0)) satisfies T2; +const t6 = [1, 2] satisfies [number, number]; +let t7 = { a: 'test' } satisfies A; +let t8 = { a: 'test', b: 'test' } satisfies A; + +const p = { + isEven: n => n % 2 === 0, + isOdd: n => n % 2 === 1 +} satisfies Predicates; + +let obj: { f(s: string): void } & Record = { + f(s) { }, + g(s) { } +} satisfies { g(s: string): void } & Record; + +({ f(x) { } }) satisfies { f(s: string): void }; + +const car = { + start() { }, + move(d) { + // d should be number + }, + stop() { } +} satisfies Movable & Record; + +var v = undefined satisfies 1; diff --git a/tests/format/typescript/satisfies-operators/comments-unstable.ts b/tests/format/typescript/satisfies-operators/comments-unstable.ts new file mode 100644 index 000000000000..0f658aa54605 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/comments-unstable.ts @@ -0,0 +1,7 @@ +const t1 = { + prop1: 1, + prop2: 2, + prop3: 3 +} satisfies +// Comment +Record; diff --git a/tests/format/typescript/satisfies-operators/comments.ts b/tests/format/typescript/satisfies-operators/comments.ts new file mode 100644 index 000000000000..9ab0ae58c20c --- /dev/null +++ b/tests/format/typescript/satisfies-operators/comments.ts @@ -0,0 +1,3 @@ +const t2 = {} /* comment */ satisfies {}; +const t3 = {} satisfies /* comment */ {}; +const t4 = {} /* comment1 */ satisfies /* comment2 */ {}; diff --git a/tests/format/typescript/satisfies-operators/export-default-as.ts b/tests/format/typescript/satisfies-operators/export-default-as.ts new file mode 100644 index 000000000000..6d6905150d89 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/export-default-as.ts @@ -0,0 +1 @@ +export default (function log() {} satisfies typeof console.log) diff --git a/tests/format/typescript/satisfies-operators/gt-lt.ts b/tests/format/typescript/satisfies-operators/gt-lt.ts new file mode 100644 index 000000000000..bdc95deefbed --- /dev/null +++ b/tests/format/typescript/satisfies-operators/gt-lt.ts @@ -0,0 +1,2 @@ +x satisfies boolean <= y; // (x satisfies boolean) <= y; +x satisfies boolean ?? y; // (x satisfies boolean) ?? y; diff --git a/tests/format/typescript/satisfies-operators/hug-args.ts b/tests/format/typescript/satisfies-operators/hug-args.ts new file mode 100644 index 000000000000..c35cf66fb521 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/hug-args.ts @@ -0,0 +1,6 @@ +window.postMessage( + { + context: item.context, + topic: item.topic + } satisfies IActionMessage + ); diff --git a/tests/format/typescript/satisfies-operators/jsfmt.spec.js b/tests/format/typescript/satisfies-operators/jsfmt.spec.js new file mode 100644 index 000000000000..9b9787422054 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/jsfmt.spec.js @@ -0,0 +1,2 @@ +run_spec(import.meta, ["babel-ts"]); +run_spec(import.meta, ["babel-ts"], { semi: false }); diff --git a/tests/format/typescript/satisfies-operators/nested-await-and-satisfies.ts b/tests/format/typescript/satisfies-operators/nested-await-and-satisfies.ts new file mode 100644 index 000000000000..d9c2b4a600be --- /dev/null +++ b/tests/format/typescript/satisfies-operators/nested-await-and-satisfies.ts @@ -0,0 +1,7 @@ +const getAccountCount = async () => + (await + ((await ( + await focusOnSection(BOOKMARKED_PROJECTS_SECTION_NAME) + ).findItem("My bookmarks")) satisfies TreeItem + ).getChildren() + ).length diff --git a/tests/format/typescript/satisfies-operators/non-null.ts b/tests/format/typescript/satisfies-operators/non-null.ts new file mode 100644 index 000000000000..9e1e0b3ac0b0 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/non-null.ts @@ -0,0 +1,3 @@ +// the 2nd line needs ASI protection +const el = ReactDOM.findDOMNode(ref) +;(el satisfies HTMLElement)!.style.cursor = 'pointer' diff --git a/tests/format/typescript/satisfies-operators/satisfies.ts b/tests/format/typescript/satisfies-operators/satisfies.ts new file mode 100644 index 000000000000..f9b3f6f2acb3 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/satisfies.ts @@ -0,0 +1,22 @@ +({}) satisfies {}; +({}) satisfies X; +() => ({}) satisfies X; +this.isTabActionBar((e.target || e.srcElement) satisfies HTMLElement); + +'current' in (props.pagination satisfies Object); +('current' in props.pagination) satisfies Object; +start + (yearSelectTotal satisfies number); +(start + yearSelectTotal) satisfies number; +scrollTop > (visibilityHeight satisfies number); +(scrollTop > visibilityHeight) satisfies number; +(bValue satisfies boolean) ? 0 : -1; + +async function g1() { + const test = (await 'foo') satisfies number; +} + +var x = (v => v) satisfies (x: number) => string; + +foo satisfies unknown satisfies Bar; +foo satisfies unknown as Bar; +foo as unknown satisfies Bar; diff --git a/tests/format/typescript/satisfies-operators/template-literal.ts b/tests/format/typescript/satisfies-operators/template-literal.ts new file mode 100644 index 000000000000..d4152adc97e5 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/template-literal.ts @@ -0,0 +1,5 @@ +const a = `${(foo + bar) satisfies baz}`; +const b = `${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + bar) satisfies baz}`; +const b = `${(foo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies baz}`; +const b = `${(foo + bar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}`; +const b = `${(veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongFoo + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBar) satisfies veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongBaz}`; diff --git a/tests/format/typescript/satisfies-operators/ternary.ts b/tests/format/typescript/satisfies-operators/ternary.ts new file mode 100644 index 000000000000..0baab89c6c37 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/ternary.ts @@ -0,0 +1,40 @@ +foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +foo = (condition ? firstValue : secondValue) satisfies SomeType; + +const foo = (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; + +function foo() { + return (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + throw (coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo; +} + +function foo() { + void ((coooooooooooooooooooooooooooooooooooooooooooooooooooond + ? baaaaaaaaaaaaaaaaaaaaar + : baaaaaaaaaaaaaaaaaaaaaz) satisfies Fooooooooooo); +} + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); + +bifornCringerMoshedPerplexSawder = + askTrovenaBeenaDependsRowans + + ((glimseGlyphsHazardNoopsTieTie === 0 && + kochabCooieGameOnOboleUnweave === Math.PI + ? averredBathersBoxroomBuggyNurl + : anodyneCondosMalateOverateRetinol) satisfies AnnularCooeedSplicesWalksWayWay); diff --git a/tests/format/typescript/satisfies-operators/types-comments.ts b/tests/format/typescript/satisfies-operators/types-comments.ts new file mode 100644 index 000000000000..8ef9413c2a31 --- /dev/null +++ b/tests/format/typescript/satisfies-operators/types-comments.ts @@ -0,0 +1,3 @@ +(() => { + // swallow error and fallback to using directory as path +}) satisfies string[];