diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 896e2e77145ca..80a2f2d7b968f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -947,6 +947,7 @@ import { ReverseMappedSymbol, ReverseMappedType, sameMap, + SatisfiesClause, SatisfiesExpression, scanTokenAtPosition, ScriptKind, @@ -7797,7 +7798,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { kind === SyntaxKind.JSDocFunctionType ? factory.createJSDocFunctionType(parameters, returnTypeNode) : kind === SyntaxKind.FunctionType ? factory.createFunctionTypeNode(typeParameters, parameters, returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier(""))) : kind === SyntaxKind.ConstructorType ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier(""))) : - kind === SyntaxKind.FunctionDeclaration ? factory.createFunctionDeclaration(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, /*body*/ undefined) : + kind === SyntaxKind.FunctionDeclaration ? factory.createFunctionDeclaration(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, /*body*/ undefined, /*satisfiesClause*/ undefined) : kind === SyntaxKind.FunctionExpression ? factory.createFunctionExpression(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, factory.createBlock([])) : kind === SyntaxKind.ArrowFunction ? factory.createArrowFunction(modifiers, typeParameters, parameters, returnTypeNode, /*equalsGreaterThanToken*/ undefined, factory.createBlock([])) : Debug.assertNever(kind); @@ -9684,6 +9685,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { typeParamDecls, heritageClauses, [...indexSignatures, ...staticMembers, ...constructors, ...publicProperties, ...privateProperties], + /*satisfiesClause*/ undefined, ), symbol.declarations && filter(symbol.declarations, d => isClassDeclaration(d) || isClassExpression(d))[0], ), @@ -36480,6 +36482,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + function checkSatisfiesClause(sourceType: Type, node: SatisfiesClause) { + checkSourceElement(node.type); + const targetType = getTypeFromTypeNode(node.type); + if (isErrorType(targetType)) { + return targetType; + } + checkTypeAssignableToAndOptionallyElaborate(sourceType, targetType, node, /*expr*/ undefined, Diagnostics.Type_0_does_not_satisfy_the_expected_type_1); + } + function checkSatisfiesExpression(node: SatisfiesExpression) { checkSourceElement(node.type); return checkSatisfiesExpressionWorker(node.expression, node.type); @@ -42403,6 +42414,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + if (isFunctionDeclaration(node) && node.satisfiesClause) { + checkSatisfiesClause(getTypeOfSymbol(getSymbolOfDeclaration(node)), node.satisfiesClause); + } + function checkFunctionOrMethodDeclarationDiagnostics() { if (!getEffectiveReturnTypeNode(node)) { // Report an implicit any error if there is no body, no explicit return type, and node is not a private method @@ -45004,7 +45019,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } checkClassLikeDeclaration(node); forEach(node.members, checkSourceElement); - + if (node.satisfiesClause) { + checkSatisfiesClause(getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(node)), node.satisfiesClause); + } registerForUnusedIdentifiersCheck(node); } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 021b4e24881e6..0d5ea8ba426a6 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -353,6 +353,7 @@ import { resolvePath, RestTypeNode, ReturnStatement, + SatisfiesClause, SatisfiesExpression, ScriptTarget, setOriginalNode, @@ -1742,6 +1743,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return emitHeritageClause(node as HeritageClause); case SyntaxKind.CatchClause: return emitCatchClause(node as CatchClause); + case SyntaxKind.SatisfiesClause: + return emitSatisfiesClause(node as SatisfiesClause); // Property assignments case SyntaxKind.PropertyAssignment: @@ -3292,6 +3295,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitFunctionDeclaration(node: FunctionDeclaration) { emitFunctionDeclarationOrExpression(node); + if (node.satisfiesClause) { + emit(node.satisfiesClause); + } } function emitFunctionDeclarationOrExpression(node: FunctionDeclaration | FunctionExpression) { @@ -3420,6 +3426,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitClassDeclaration(node: ClassDeclaration) { emitClassDeclarationOrExpression(node); + if (node.satisfiesClause) { + emit(node.satisfiesClause); + } } function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) { @@ -3916,6 +3925,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emit(node.block); } + function emitSatisfiesClause(node: SatisfiesClause) { + writeSpace(); + emitTokenWithComment(SyntaxKind.SatisfiesKeyword, node.pos, writeKeyword, node); + writeSpace(); + emit(node.type); + } + // // Property assignments // diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 76e084c90d8f0..da32004cc6f97 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -379,6 +379,7 @@ import { ReturnStatement, returnTrue, sameFlatMap, + SatisfiesClause, SatisfiesExpression, Scanner, ScriptTarget, @@ -990,6 +991,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode updateHeritageClause, createCatchClause, updateCatchClause, + createSatisfiesClause, + updateSatisfiesClause, createPropertyAssignment, updatePropertyAssignment, createShorthandPropertyAssignment, @@ -4294,6 +4297,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined, + satisfiesClause: SatisfiesClause | undefined, ) { const node = createBaseDeclaration(SyntaxKind.FunctionDeclaration); node.modifiers = asNodeArray(modifiers); @@ -4303,6 +4307,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.parameters = createNodeArray(parameters); node.type = type; node.body = body; + node.satisfiesClause = satisfiesClause; if (!node.body || modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) { node.transformFlags = TransformFlags.ContainsTypeScript; @@ -4346,6 +4351,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined, + satisfiesClause: SatisfiesClause | undefined, ) { return node.modifiers !== modifiers || node.asteriskToken !== asteriskToken @@ -4354,7 +4360,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode || node.parameters !== parameters || node.type !== type || node.body !== body - ? finishUpdateFunctionDeclaration(createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body), node) + || node.satisfiesClause !== satisfiesClause + ? finishUpdateFunctionDeclaration(createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body, satisfiesClause), node) : node; } @@ -4375,6 +4382,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[], + satisfiesClause: SatisfiesClause | undefined, ) { const node = createBaseDeclaration(SyntaxKind.ClassDeclaration); node.modifiers = asNodeArray(modifiers); @@ -4382,6 +4390,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.typeParameters = asNodeArray(typeParameters); node.heritageClauses = asNodeArray(heritageClauses); node.members = createNodeArray(members); + node.satisfiesClause = satisfiesClause; if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) { node.transformFlags = TransformFlags.ContainsTypeScript; @@ -4411,13 +4420,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[], + satisfiesClause: SatisfiesClause | undefined, ) { return node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.heritageClauses !== heritageClauses || node.members !== members - ? update(createClassDeclaration(modifiers, name, typeParameters, heritageClauses, members), node) + || node.satisfiesClause !== satisfiesClause + ? update(createClassDeclaration(modifiers, name, typeParameters, heritageClauses, members, satisfiesClause), node) : node; } @@ -5897,6 +5908,21 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode : node; } + // @api + function createSatisfiesClause(type: TypeNode) { + const node = createBaseNode(SyntaxKind.SatisfiesClause); + node.type = type; + node.transformFlags = TransformFlags.ContainsTypeScript; + return node; + } + + // @api + function updateSatisfiesClause(node: SatisfiesClause, type: TypeNode) { + return node.type !== type + ? update(createSatisfiesClause(type), node) + : node; + } + // // Property assignments // @@ -7064,8 +7090,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode isArrowFunction(node) ? updateArrowFunction(node, modifierArray, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, node.body) : isClassExpression(node) ? updateClassExpression(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : isVariableStatement(node) ? updateVariableStatement(node, modifierArray, node.declarationList) : - isFunctionDeclaration(node) ? updateFunctionDeclaration(node, modifierArray, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body) : - isClassDeclaration(node) ? updateClassDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : + isFunctionDeclaration(node) ? updateFunctionDeclaration(node, modifierArray, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body, node.satisfiesClause) : + isClassDeclaration(node) ? updateClassDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members, node.satisfiesClause) : isInterfaceDeclaration(node) ? updateInterfaceDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : isTypeAliasDeclaration(node) ? updateTypeAliasDeclaration(node, modifierArray, node.name, node.typeParameters, node.type) : isEnumDeclaration(node) ? updateEnumDeclaration(node, modifierArray, node.name, node.members) : @@ -7085,7 +7111,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode isGetAccessorDeclaration(node) ? updateGetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.type, node.body) : isSetAccessorDeclaration(node) ? updateSetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.body) : isClassExpression(node) ? updateClassExpression(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : - isClassDeclaration(node) ? updateClassDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : + isClassDeclaration(node) ? updateClassDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members, node.satisfiesClause) : Debug.assertNever(node); } diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index 012616ac5dc70..560657602f9c2 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -182,6 +182,7 @@ import { RegularExpressionLiteral, RestTypeNode, ReturnStatement, + SatisfiesClause, SatisfiesExpression, SemicolonClassElement, SetAccessorDeclaration, @@ -985,6 +986,10 @@ export function isCatchClause(node: Node): node is CatchClause { return node.kind === SyntaxKind.CatchClause; } +export function isSatisfiesClause(node: Node): node is SatisfiesClause { + return node.kind === SyntaxKind.SatisfiesClause; +} + // Property assignments export function isPropertyAssignment(node: Node): node is PropertyAssignment { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ca4bb9ed61275..92701195d770f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -322,6 +322,7 @@ import { ResolutionMode, RestTypeNode, ReturnStatement, + SatisfiesClause, SatisfiesExpression, ScriptKind, ScriptTarget, @@ -632,7 +633,8 @@ const forEachChildTable: ForEachChildTable = { visitNodes(cbNode, cbNodes, node.typeParameters) || visitNodes(cbNode, cbNodes, node.parameters) || visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + visitNode(cbNode, node.body) || + visitNode(cbNode, node.satisfiesClause); }, [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression(node: FunctionExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNodes(cbNode, cbNodes, node.modifiers) || @@ -872,6 +874,9 @@ const forEachChildTable: ForEachChildTable = { [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause(node: DefaultClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNodes(cbNode, cbNodes, node.statements); }, + [SyntaxKind.SatisfiesClause]: function forEachChildInSatisfiesClause(node: SatisfiesClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + return visitNode(cbNode, node.type); + }, [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement(node: LabeledStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNode(cbNode, node.label) || visitNode(cbNode, node.statement); @@ -891,8 +896,21 @@ const forEachChildTable: ForEachChildTable = { [SyntaxKind.Decorator]: function forEachChildInDecorator(node: Decorator, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.ClassDeclaration]: forEachChildInClassDeclarationOrExpression, - [SyntaxKind.ClassExpression]: forEachChildInClassDeclarationOrExpression, + [SyntaxKind.ClassDeclaration]: function forEachChildInClassDeclaration(node: ClassDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, node.name) || + visitNodes(cbNode, cbNodes, node.typeParameters) || + visitNodes(cbNode, cbNodes, node.heritageClauses) || + visitNodes(cbNode, cbNodes, node.members) || + visitNode(cbNode, node.satisfiesClause); + }, + [SyntaxKind.ClassExpression]: function forEachChildInClassExpression(node: ClassExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) || + visitNode(cbNode, node.name) || + visitNodes(cbNode, cbNodes, node.typeParameters) || + visitNodes(cbNode, cbNodes, node.heritageClauses) || + visitNodes(cbNode, cbNodes, node.members); + }, [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration(node: InterfaceDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNodes(cbNode, cbNodes, node.modifiers) || visitNode(cbNode, node.name) || @@ -1166,14 +1184,6 @@ function forEachChildInContinueOrBreakStatement(node: ContinueStatement | Bre return visitNode(cbNode, node.label); } -function forEachChildInClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.heritageClauses) || - visitNodes(cbNode, cbNodes, node.members); -} - function forEachChildInNamedImportsOrExports(node: NamedImports | NamedExports, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); } @@ -7697,10 +7707,20 @@ namespace Parser { const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected); setAwaitContext(savedAwaitContext); - const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body); + const satisfiesClause = parseSatisfiesClause(); + const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body, satisfiesClause); return withJSDoc(finishNode(node, pos), hasJSDoc); } + function parseSatisfiesClause() { + if (parseOptional(SyntaxKind.SatisfiesKeyword)) { + const pos = getNodePos(); + const type = parseType(); + return finishNode(factory.createSatisfiesClause(type), pos); + } + return undefined; + } + function parseConstructorName() { if (token() === SyntaxKind.ConstructorKeyword) { return parseExpected(SyntaxKind.ConstructorKeyword); @@ -8123,7 +8143,7 @@ namespace Parser { } setAwaitContext(savedAwaitContext); const node = kind === SyntaxKind.ClassDeclaration - ? factory.createClassDeclaration(modifiers, name, typeParameters, heritageClauses, members) + ? factory.createClassDeclaration(modifiers, name, typeParameters, heritageClauses, members, parseSatisfiesClause()) : factory.createClassExpression(modifiers, name, typeParameters, heritageClauses, members); return withJSDoc(finishNode(node, pos), hasJSDoc); } diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts index ede44357f242d..f533bee9d58fa 100644 --- a/src/compiler/transformers/classFields.ts +++ b/src/compiler/transformers/classFields.ts @@ -1941,6 +1941,7 @@ export function transformClassFields(context: TransformationContext): (x: Source /*typeParameters*/ undefined, heritageClauses, members, + /*satisfiesClause*/ undefined, ); statements.unshift(classDecl); diff --git a/src/compiler/transformers/classThis.ts b/src/compiler/transformers/classThis.ts index 48f51ea8477c4..70d60674ced6a 100644 --- a/src/compiler/transformers/classThis.ts +++ b/src/compiler/transformers/classThis.ts @@ -134,6 +134,7 @@ export function injectClassThisAssignmentIfMissing; readonly name?: Identifier; readonly body?: FunctionBody; + readonly satisfiesClause?: SatisfiesClause; } export interface MethodSignature extends SignatureDeclarationBase, TypeElement, LocalsContainer { @@ -3483,6 +3486,7 @@ export interface ClassDeclaration extends ClassLikeDeclarationBase, DeclarationS readonly modifiers?: NodeArray; /** May be undefined in `export default class { ... }`. */ readonly name?: Identifier; + readonly satisfiesClause?: SatisfiesClause; } export interface ClassExpression extends ClassLikeDeclarationBase, PrimaryExpression { @@ -3521,6 +3525,12 @@ export interface HeritageClause extends Node { readonly types: NodeArray; } +export interface SatisfiesClause extends Node { + readonly kind: SyntaxKind.SatisfiesClause; + readonly parent: FunctionDeclaration | ClassDeclaration; + readonly type: TypeNode; +} + export interface TypeAliasDeclaration extends DeclarationStatement, JSDocContainer, LocalsContainer { readonly kind: SyntaxKind.TypeAliasDeclaration; readonly modifiers?: NodeArray; @@ -8652,10 +8662,10 @@ export interface NodeFactory { updateVariableDeclaration(node: VariableDeclaration, name: BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): VariableDeclaration; createVariableDeclarationList(declarations: readonly VariableDeclaration[], flags?: NodeFlags): VariableDeclarationList; updateVariableDeclarationList(node: VariableDeclarationList, declarations: readonly VariableDeclaration[]): VariableDeclarationList; - createFunctionDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration; - updateFunctionDeclaration(node: FunctionDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration; - createClassDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration; - updateClassDeclaration(node: ClassDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration; + createFunctionDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined, satisfiesClause: SatisfiesClause | undefined): FunctionDeclaration; + updateFunctionDeclaration(node: FunctionDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined, satisfiesClause: SatisfiesClause | undefined): FunctionDeclaration; + createClassDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[], satisfiesClause: SatisfiesClause | undefined): ClassDeclaration; + updateClassDeclaration(node: ClassDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[], satisfiesClause: SatisfiesClause | undefined): ClassDeclaration; createInterfaceDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration; updateInterfaceDeclaration(node: InterfaceDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration; createTypeAliasDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; @@ -8842,6 +8852,8 @@ export interface NodeFactory { updateHeritageClause(node: HeritageClause, types: readonly ExpressionWithTypeArguments[]): HeritageClause; createCatchClause(variableDeclaration: string | BindingName | VariableDeclaration | undefined, block: Block): CatchClause; updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block): CatchClause; + createSatisfiesClause(type: TypeNode): SatisfiesClause; + updateSatisfiesClause(node: SatisfiesClause, type: TypeNode): SatisfiesClause; // // Property assignments diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 328e1b2f0e55c..1a1bb049e6c7b 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -1786,6 +1786,10 @@ export function isFunctionOrConstructorTypeNode(node: Node): node is FunctionTyp return false; } +export function isTypeOrFunctionOrConstructorTypeNode(node: Node): node is TypeNode | FunctionTypeNode | ConstructorTypeNode { + return isTypeNode(node) || isFunctionOrConstructorTypeNode(node); +} + // Binding patterns /** @internal */ diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index 0a4c746c2e7c6..35c99852a6b49 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -73,6 +73,7 @@ import { isQuestionOrPlusOrMinusToken, isQuestionToken, isReadonlyKeywordOrPlusOrMinusToken, + isSatisfiesClause, isStatement, isStringLiteralOrJsxExpression, isTemplateHead, @@ -1435,6 +1436,7 @@ const visitEachChildTable: VisitEachChildTable = { visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), visitFunctionBody(node.body, visitor, context, nodeVisitor), + nodeVisitor(node.satisfiesClause, visitor, isSatisfiesClause), ); }, @@ -1446,6 +1448,7 @@ const visitEachChildTable: VisitEachChildTable = { nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.heritageClauses, visitor, isHeritageClause), nodesVisitor(node.members, visitor, isClassElement), + nodeVisitor(node.satisfiesClause, visitor, isSatisfiesClause), ); }, @@ -1739,6 +1742,13 @@ const visitEachChildTable: VisitEachChildTable = { ); }, + [SyntaxKind.SatisfiesClause]: function visitEachChildOfSatisfiesClause(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + return context.factory.updateSatisfiesClause( + node, + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); + }, + // Property assignments [SyntaxKind.PropertyAssignment]: function visitEachChildOfPropertyAssignment(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updatePropertyAssignment( diff --git a/src/services/codefixes/convertFunctionToEs6Class.ts b/src/services/codefixes/convertFunctionToEs6Class.ts index 92d1c85f269f6..d0c38797ccae5 100644 --- a/src/services/codefixes/convertFunctionToEs6Class.ts +++ b/src/services/codefixes/convertFunctionToEs6Class.ts @@ -292,7 +292,7 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po } const modifiers = getModifierKindFromSource(node.parent.parent, SyntaxKind.ExportKeyword); - const cls = factory.createClassDeclaration(modifiers, node.name, /*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements); + const cls = factory.createClassDeclaration(modifiers, node.name, /*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements, /*satisfiesClause*/ undefined); // Don't call copyComments here because we'll already leave them in place return cls; } @@ -304,7 +304,7 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po } const modifiers = getModifierKindFromSource(node, SyntaxKind.ExportKeyword); - const cls = factory.createClassDeclaration(modifiers, node.name, /*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements); + const cls = factory.createClassDeclaration(modifiers, node.name, /*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements, /*satisfiesClause*/ undefined); // Don't call copyComments here because we'll already leave them in place return cls; } diff --git a/src/services/codefixes/convertToEsModule.ts b/src/services/codefixes/convertToEsModule.ts index b78669dc244a0..772b428479197 100644 --- a/src/services/codefixes/convertToEsModule.ts +++ b/src/services/codefixes/convertToEsModule.ts @@ -637,6 +637,7 @@ function functionExpressionToDeclaration(name: string | undefined, additionalMod getSynthesizedDeepClones(fn.parameters), getSynthesizedDeepClone(fn.type), factory.converters.convertToFunctionBlock(replaceImportUseSites(fn.body!, useSitesToUnqualify)), + /*satisfiesClause*/ undefined, ); } @@ -647,6 +648,7 @@ function classExpressionToDeclaration(name: string | undefined, additionalModifi getSynthesizedDeepClones(cls.typeParameters), getSynthesizedDeepClones(cls.heritageClauses), replaceImportUseSites(cls.members, useSitesToUnqualify), + /*satisfiesClause*/ undefined, ); } diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 5e6dd79755636..52c57f015f262 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -474,7 +474,7 @@ export function createSignatureDeclarationFromSignature( return factory.updateMethodDeclaration(signatureDeclaration, modifiers, asteriskToken, name ?? factory.createIdentifier(""), questionToken, typeParameters, parameters, type, body); } if (isFunctionDeclaration(signatureDeclaration)) { - return factory.updateFunctionDeclaration(signatureDeclaration, modifiers, signatureDeclaration.asteriskToken, tryCast(name, isIdentifier), typeParameters, parameters, type, body ?? signatureDeclaration.body); + return factory.updateFunctionDeclaration(signatureDeclaration, modifiers, signatureDeclaration.asteriskToken, tryCast(name, isIdentifier), typeParameters, parameters, type, body ?? signatureDeclaration.body, signatureDeclaration.satisfiesClause); } return undefined; } @@ -552,6 +552,7 @@ export function createSignatureDeclarationFromCallExpression( parameters, type, createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), + /*satisfiesClause*/ undefined, ); default: Debug.fail("Unexpected kind"); diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 39a94b032fd66..b2bfb60cd986d 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -223,6 +223,7 @@ export function getAllRules(): RuleSpec[] { SyntaxKind.FromKeyword, SyntaxKind.KeyOfKeyword, SyntaxKind.InferKeyword, + SyntaxKind.SatisfiesKeyword, ], anyToken, [isNonJsxSameLineTokenContext], diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 167ca62982e94..579b6c295197b 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -683,6 +683,7 @@ function tryMergeEs5Class(a: NavigationBarNode, b: NavigationBarNode, bIndex: nu /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [], + /*satisfiesClause*/ undefined, ), a.node, ); @@ -713,6 +714,7 @@ function tryMergeEs5Class(a: NavigationBarNode, b: NavigationBarNode, bIndex: nu /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [], + /*satisfiesClause*/ undefined, ), b.node, )); diff --git a/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts index 05d13bdc8fd91..fb0cd3d2e6a76 100644 --- a/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts +++ b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts @@ -274,7 +274,7 @@ function getEditInfoForConvertToNamedFunction(context: RefactorContext, func: Fu const modifiersFlags = (getCombinedModifierFlags(variableDeclaration) & ModifierFlags.Export) | getEffectiveModifierFlags(func); const modifiers = factory.createModifiersFromModifierFlags(modifiersFlags); - const newNode = factory.createFunctionDeclaration(length(modifiers) ? modifiers : undefined, func.asteriskToken, name, func.typeParameters, func.parameters, func.type, body); + const newNode = factory.createFunctionDeclaration(length(modifiers) ? modifiers : undefined, func.asteriskToken, name, func.typeParameters, func.parameters, func.type, body, /*satisfiesClause*/ undefined); if (variableDeclarationList.declarations.length === 1) { return textChanges.ChangeTracker.with(context, t => t.replaceNode(file, statement, newNode)); diff --git a/src/services/refactors/convertOverloadListToSingleSignature.ts b/src/services/refactors/convertOverloadListToSingleSignature.ts index 6eccdbb06af61..2389cd894e3f2 100644 --- a/src/services/refactors/convertOverloadListToSingleSignature.ts +++ b/src/services/refactors/convertOverloadListToSingleSignature.ts @@ -143,6 +143,7 @@ function getRefactorEditsToConvertOverloadsToOneSignature(context: RefactorConte getNewParametersForCombinedSignature(signatureDecls), lastDeclaration.type, lastDeclaration.body, + lastDeclaration.satisfiesClause, ); break; } diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 484112be14421..b0688e8adebf6 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -1152,6 +1152,7 @@ function extractFunctionInScope( parameters, returnType, body, + /*satisfiesClause*/ undefined, ); } diff --git a/src/services/refactors/moveToFile.ts b/src/services/refactors/moveToFile.ts index a84da0a381a12..c0ec36e3b3792 100644 --- a/src/services/refactors/moveToFile.ts +++ b/src/services/refactors/moveToFile.ts @@ -732,10 +732,10 @@ function addEs6Export(d: TopLevelDeclarationStatement): TopLevelDeclarationState const modifiers = canHaveModifiers(d) ? concatenate([factory.createModifier(SyntaxKind.ExportKeyword)], getModifiers(d)) : undefined; switch (d.kind) { case SyntaxKind.FunctionDeclaration: - return factory.updateFunctionDeclaration(d, modifiers, d.asteriskToken, d.name, d.typeParameters, d.parameters, d.type, d.body); + return factory.updateFunctionDeclaration(d, modifiers, d.asteriskToken, d.name, d.typeParameters, d.parameters, d.type, d.body, d.satisfiesClause); case SyntaxKind.ClassDeclaration: const decorators = canHaveDecorators(d) ? getDecorators(d) : undefined; - return factory.updateClassDeclaration(d, concatenate(decorators, modifiers), d.name, d.typeParameters, d.heritageClauses, d.members); + return factory.updateClassDeclaration(d, concatenate(decorators, modifiers), d.name, d.typeParameters, d.heritageClauses, d.members, d.satisfiesClause); case SyntaxKind.VariableStatement: return factory.updateVariableStatement(d, modifiers, d.declarationList); case SyntaxKind.ModuleDeclaration: diff --git a/src/testRunner/unittests/printer.ts b/src/testRunner/unittests/printer.ts index dd724ed73f855..66b169d3e38f3 100644 --- a/src/testRunner/unittests/printer.ts +++ b/src/testRunner/unittests/printer.ts @@ -181,6 +181,7 @@ describe("unittests:: PrinterAPI", () => { /*type*/ undefined, /*initializer*/ undefined, )], + /*satisfiesClause*/ undefined, ), ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015), )); @@ -275,6 +276,7 @@ describe("unittests:: PrinterAPI", () => { /*initializer*/ undefined, ), ], + /*satisfiesClause*/ undefined, ), ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015), )); diff --git a/src/testRunner/unittests/services/textChanges.ts b/src/testRunner/unittests/services/textChanges.ts index 57b3e206ef283..1a9a0daa672b6 100644 --- a/src/testRunner/unittests/services/textChanges.ts +++ b/src/testRunner/unittests/services/textChanges.ts @@ -95,6 +95,7 @@ namespace M /*parameters*/ ts.emptyArray, /*type*/ ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), /*body */ ts.factory.createBlock(statements), + /*satisfiesClause*/ undefined, ); changeTracker.insertNodeBefore(sourceFile, /*before*/ findChild("M2", sourceFile), newFunction); @@ -206,6 +207,7 @@ var a = 4; // comment 7 /*initializer*/ undefined, ), ], + /*satisfiesClause*/ undefined, ); } { diff --git a/src/testRunner/unittests/transform.ts b/src/testRunner/unittests/transform.ts index 85b10333a0fbc..03b10e147c6f0 100644 --- a/src/testRunner/unittests/transform.ts +++ b/src/testRunner/unittests/transform.ts @@ -264,7 +264,7 @@ describe("unittests:: TransformAPI", () => { const result = ts.factory.updateSourceFile( sourceFile, ts.factory.createNodeArray([ - ts.factory.createClassDeclaration(/*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, /*members*/ undefined!), // TODO: GH#18217 + ts.factory.createClassDeclaration(/*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, /*members*/ undefined!, /*satisfiesClause*/ undefined), // TODO: GH#18217 ts.factory.createModuleDeclaration(/*modifiers*/ undefined, ts.factory.createIdentifier("Foo"), ts.factory.createModuleBlock([ts.factory.createEmptyStatement()])), ]), ); @@ -375,7 +375,7 @@ describe("unittests:: TransformAPI", () => { // produce `class Foo { @Bar baz() {} }`; const classDecl = ts.factory.createClassDeclaration(/*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [ ts.factory.createMethodDeclaration([ts.factory.createDecorator(ts.factory.createIdentifier("Bar"))], /*asteriskToken*/ undefined, "baz", /*questionToken*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, ts.factory.createBlock([])), - ]); + ], /*satisfiesClause*/ undefined); return ts.factory.updateSourceFile(sf, [classDecl]); } } @@ -417,7 +417,7 @@ describe("unittests:: TransformAPI", () => { ts.factory.createConstructorDeclaration(/*modifiers*/ undefined, [ ts.factory.createParameterDeclaration([ts.factory.createDecorator(ts.factory.createIdentifier("Dec")), ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword)], /*dotDotDotToken*/ undefined, "x"), ], ts.factory.createBlock([])), - ]); + ], /*satisfiesClause*/ undefined); return ts.factory.updateSourceFile(sf, [classDecl]); } } @@ -668,6 +668,7 @@ module MyModule { node.typeParameters, node.heritageClauses, newMembers, + node.satisfiesClause, ) : ts.factory.updateClassExpression( node, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 7f7bf51496508..b7bf74ffe5c1d 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3887,68 +3887,69 @@ declare namespace ts { DefaultClause = 297, HeritageClause = 298, CatchClause = 299, - ImportAttributes = 300, - ImportAttribute = 301, - /** @deprecated */ AssertClause = 300, - /** @deprecated */ AssertEntry = 301, - /** @deprecated */ ImportTypeAssertionContainer = 302, - PropertyAssignment = 303, - ShorthandPropertyAssignment = 304, - SpreadAssignment = 305, - EnumMember = 306, - SourceFile = 307, - Bundle = 308, - JSDocTypeExpression = 309, - JSDocNameReference = 310, - JSDocMemberName = 311, - JSDocAllType = 312, - JSDocUnknownType = 313, - JSDocNullableType = 314, - JSDocNonNullableType = 315, - JSDocOptionalType = 316, - JSDocFunctionType = 317, - JSDocVariadicType = 318, - JSDocNamepathType = 319, - JSDoc = 320, + SatisfiesClause = 300, + ImportAttributes = 301, + ImportAttribute = 302, + /** @deprecated */ AssertClause = 301, + /** @deprecated */ AssertEntry = 302, + /** @deprecated */ ImportTypeAssertionContainer = 303, + PropertyAssignment = 304, + ShorthandPropertyAssignment = 305, + SpreadAssignment = 306, + EnumMember = 307, + SourceFile = 308, + Bundle = 309, + JSDocTypeExpression = 310, + JSDocNameReference = 311, + JSDocMemberName = 312, + JSDocAllType = 313, + JSDocUnknownType = 314, + JSDocNullableType = 315, + JSDocNonNullableType = 316, + JSDocOptionalType = 317, + JSDocFunctionType = 318, + JSDocVariadicType = 319, + JSDocNamepathType = 320, + JSDoc = 321, /** @deprecated Use SyntaxKind.JSDoc */ - JSDocComment = 320, - JSDocText = 321, - JSDocTypeLiteral = 322, - JSDocSignature = 323, - JSDocLink = 324, - JSDocLinkCode = 325, - JSDocLinkPlain = 326, - JSDocTag = 327, - JSDocAugmentsTag = 328, - JSDocImplementsTag = 329, - JSDocAuthorTag = 330, - JSDocDeprecatedTag = 331, - JSDocClassTag = 332, - JSDocPublicTag = 333, - JSDocPrivateTag = 334, - JSDocProtectedTag = 335, - JSDocReadonlyTag = 336, - JSDocOverrideTag = 337, - JSDocCallbackTag = 338, - JSDocOverloadTag = 339, - JSDocEnumTag = 340, - JSDocParameterTag = 341, - JSDocReturnTag = 342, - JSDocThisTag = 343, - JSDocTypeTag = 344, - JSDocTemplateTag = 345, - JSDocTypedefTag = 346, - JSDocSeeTag = 347, - JSDocPropertyTag = 348, - JSDocThrowsTag = 349, - JSDocSatisfiesTag = 350, - JSDocImportTag = 351, - SyntaxList = 352, - NotEmittedStatement = 353, - PartiallyEmittedExpression = 354, - CommaListExpression = 355, - SyntheticReferenceExpression = 356, - Count = 357, + JSDocComment = 321, + JSDocText = 322, + JSDocTypeLiteral = 323, + JSDocSignature = 324, + JSDocLink = 325, + JSDocLinkCode = 326, + JSDocLinkPlain = 327, + JSDocTag = 328, + JSDocAugmentsTag = 329, + JSDocImplementsTag = 330, + JSDocAuthorTag = 331, + JSDocDeprecatedTag = 332, + JSDocClassTag = 333, + JSDocPublicTag = 334, + JSDocPrivateTag = 335, + JSDocProtectedTag = 336, + JSDocReadonlyTag = 337, + JSDocOverrideTag = 338, + JSDocCallbackTag = 339, + JSDocOverloadTag = 340, + JSDocEnumTag = 341, + JSDocParameterTag = 342, + JSDocReturnTag = 343, + JSDocThisTag = 344, + JSDocTypeTag = 345, + JSDocTemplateTag = 346, + JSDocTypedefTag = 347, + JSDocSeeTag = 348, + JSDocPropertyTag = 349, + JSDocThrowsTag = 350, + JSDocSatisfiesTag = 351, + JSDocImportTag = 352, + SyntaxList = 353, + NotEmittedStatement = 354, + PartiallyEmittedExpression = 355, + CommaListExpression = 356, + SyntheticReferenceExpression = 357, + Count = 358, FirstAssignment = 64, LastAssignment = 79, FirstCompoundAssignment = 65, @@ -3976,10 +3977,10 @@ declare namespace ts { FirstStatement = 243, LastStatement = 259, FirstNode = 166, - FirstJSDocNode = 309, - LastJSDocNode = 351, - FirstJSDocTagNode = 327, - LastJSDocTagNode = 351, + FirstJSDocNode = 310, + LastJSDocNode = 352, + FirstJSDocTagNode = 328, + LastJSDocTagNode = 352, } type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia; type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -4559,6 +4560,7 @@ declare namespace ts { readonly modifiers?: NodeArray; readonly name?: Identifier; readonly body?: FunctionBody; + readonly satisfiesClause?: SatisfiesClause; } interface MethodSignature extends SignatureDeclarationBase, TypeElement, LocalsContainer { readonly kind: SyntaxKind.MethodSignature; @@ -5324,6 +5326,7 @@ declare namespace ts { readonly modifiers?: NodeArray; /** May be undefined in `export default class { ... }`. */ readonly name?: Identifier; + readonly satisfiesClause?: SatisfiesClause; } interface ClassExpression extends ClassLikeDeclarationBase, PrimaryExpression { readonly kind: SyntaxKind.ClassExpression; @@ -5353,6 +5356,11 @@ declare namespace ts { readonly token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword; readonly types: NodeArray; } + interface SatisfiesClause extends Node { + readonly kind: SyntaxKind.SatisfiesClause; + readonly parent: FunctionDeclaration | ClassDeclaration; + readonly type: TypeNode; + } interface TypeAliasDeclaration extends DeclarationStatement, JSDocContainer, LocalsContainer { readonly kind: SyntaxKind.TypeAliasDeclaration; readonly modifiers?: NodeArray; @@ -7577,10 +7585,10 @@ declare namespace ts { updateVariableDeclaration(node: VariableDeclaration, name: BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): VariableDeclaration; createVariableDeclarationList(declarations: readonly VariableDeclaration[], flags?: NodeFlags): VariableDeclarationList; updateVariableDeclarationList(node: VariableDeclarationList, declarations: readonly VariableDeclaration[]): VariableDeclarationList; - createFunctionDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration; - updateFunctionDeclaration(node: FunctionDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration; - createClassDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration; - updateClassDeclaration(node: ClassDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration; + createFunctionDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined, satisfiesClause: SatisfiesClause | undefined): FunctionDeclaration; + updateFunctionDeclaration(node: FunctionDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined, satisfiesClause: SatisfiesClause | undefined): FunctionDeclaration; + createClassDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[], satisfiesClause: SatisfiesClause | undefined): ClassDeclaration; + updateClassDeclaration(node: ClassDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[], satisfiesClause: SatisfiesClause | undefined): ClassDeclaration; createInterfaceDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration; updateInterfaceDeclaration(node: InterfaceDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration; createTypeAliasDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; @@ -7745,6 +7753,8 @@ declare namespace ts { updateHeritageClause(node: HeritageClause, types: readonly ExpressionWithTypeArguments[]): HeritageClause; createCatchClause(variableDeclaration: string | BindingName | VariableDeclaration | undefined, block: Block): CatchClause; updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block): CatchClause; + createSatisfiesClause(type: TypeNode): SatisfiesClause; + updateSatisfiesClause(node: SatisfiesClause, type: TypeNode): SatisfiesClause; createPropertyAssignment(name: string | PropertyName, initializer: Expression): PropertyAssignment; updatePropertyAssignment(node: PropertyAssignment, name: PropertyName, initializer: Expression): PropertyAssignment; createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer?: Expression): ShorthandPropertyAssignment; @@ -8659,6 +8669,7 @@ declare namespace ts { */ function isTypeNode(node: Node): node is TypeNode; function isFunctionOrConstructorTypeNode(node: Node): node is FunctionTypeNode | ConstructorTypeNode; + function isTypeOrFunctionOrConstructorTypeNode(node: Node): node is TypeNode | FunctionTypeNode | ConstructorTypeNode; function isArrayBindingElement(node: Node): node is ArrayBindingElement; function isPropertyAccessOrQualifiedName(node: Node): node is PropertyAccessExpression | QualifiedName; function isCallLikeExpression(node: Node): node is CallLikeExpression; @@ -8964,6 +8975,7 @@ declare namespace ts { function isDefaultClause(node: Node): node is DefaultClause; function isHeritageClause(node: Node): node is HeritageClause; function isCatchClause(node: Node): node is CatchClause; + function isSatisfiesClause(node: Node): node is SatisfiesClause; function isPropertyAssignment(node: Node): node is PropertyAssignment; function isShorthandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment; function isSpreadAssignment(node: Node): node is SpreadAssignment; diff --git a/tests/baselines/reference/typeSatisfaction.symbols b/tests/baselines/reference/typeSatisfaction.symbols deleted file mode 100644 index c518be6ea5a90..0000000000000 --- a/tests/baselines/reference/typeSatisfaction.symbols +++ /dev/null @@ -1,70 +0,0 @@ -//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction.ts] //// - -=== typeSatisfaction.ts === -interface I1 { ->I1 : Symbol(I1, Decl(typeSatisfaction.ts, 0, 0)) - - a: number; ->a : Symbol(I1.a, Decl(typeSatisfaction.ts, 0, 14)) -} - -type T1 = { ->T1 : Symbol(T1, Decl(typeSatisfaction.ts, 2, 1)) - - a: "a" | "b"; ->a : Symbol(a, Decl(typeSatisfaction.ts, 4, 11)) -} - -type T2 = (x: string) => void; ->T2 : Symbol(T2, Decl(typeSatisfaction.ts, 6, 1)) ->x : Symbol(x, Decl(typeSatisfaction.ts, 8, 11)) - -const t1 = { a: 1 } satisfies I1; // Ok ->t1 : Symbol(t1, Decl(typeSatisfaction.ts, 10, 5)) ->a : Symbol(a, Decl(typeSatisfaction.ts, 10, 12)) ->I1 : Symbol(I1, Decl(typeSatisfaction.ts, 0, 0)) - -const t2 = { a: 1, b: 1 } satisfies I1; // Error ->t2 : Symbol(t2, Decl(typeSatisfaction.ts, 11, 5)) ->a : Symbol(a, Decl(typeSatisfaction.ts, 11, 12)) ->b : Symbol(b, Decl(typeSatisfaction.ts, 11, 18)) ->I1 : Symbol(I1, Decl(typeSatisfaction.ts, 0, 0)) - -const t3 = { } satisfies I1; // Error ->t3 : Symbol(t3, Decl(typeSatisfaction.ts, 12, 5)) ->I1 : Symbol(I1, Decl(typeSatisfaction.ts, 0, 0)) - -const t4: T1 = { a: "a" } satisfies T1; // Ok ->t4 : Symbol(t4, Decl(typeSatisfaction.ts, 14, 5)) ->T1 : Symbol(T1, Decl(typeSatisfaction.ts, 2, 1)) ->a : Symbol(a, Decl(typeSatisfaction.ts, 14, 16)) ->T1 : Symbol(T1, Decl(typeSatisfaction.ts, 2, 1)) - -const t5 = (m => m.substring(0)) satisfies T2; // Ok ->t5 : Symbol(t5, Decl(typeSatisfaction.ts, 15, 5)) ->m : Symbol(m, Decl(typeSatisfaction.ts, 15, 12)) ->m.substring : Symbol(String.substring, Decl(lib.es5.d.ts, --, --)) ->m : Symbol(m, Decl(typeSatisfaction.ts, 15, 12)) ->substring : Symbol(String.substring, Decl(lib.es5.d.ts, --, --)) ->T2 : Symbol(T2, Decl(typeSatisfaction.ts, 6, 1)) - -const t6 = [1, 2] satisfies [number, number]; ->t6 : Symbol(t6, Decl(typeSatisfaction.ts, 17, 5)) - -interface A { ->A : Symbol(A, Decl(typeSatisfaction.ts, 17, 45)) - - a: string ->a : Symbol(A.a, Decl(typeSatisfaction.ts, 19, 13)) -} -let t7 = { a: 'test' } satisfies A; ->t7 : Symbol(t7, Decl(typeSatisfaction.ts, 22, 3)) ->a : Symbol(a, Decl(typeSatisfaction.ts, 22, 10)) ->A : Symbol(A, Decl(typeSatisfaction.ts, 17, 45)) - -let t8 = { a: 'test', b: 'test' } satisfies A; ->t8 : Symbol(t8, Decl(typeSatisfaction.ts, 23, 3)) ->a : Symbol(a, Decl(typeSatisfaction.ts, 23, 10)) ->b : Symbol(b, Decl(typeSatisfaction.ts, 23, 21)) ->A : Symbol(A, Decl(typeSatisfaction.ts, 17, 45)) - diff --git a/tests/baselines/reference/typeSatisfaction.errors.txt b/tests/baselines/reference/typeSatisfaction1.errors.txt similarity index 68% rename from tests/baselines/reference/typeSatisfaction.errors.txt rename to tests/baselines/reference/typeSatisfaction1.errors.txt index 21a6d33baf5f7..b7b98ae443c40 100644 --- a/tests/baselines/reference/typeSatisfaction.errors.txt +++ b/tests/baselines/reference/typeSatisfaction1.errors.txt @@ -1,10 +1,10 @@ -typeSatisfaction.ts(12,20): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'I1'. -typeSatisfaction.ts(13,16): error TS1360: Type '{}' does not satisfy the expected type 'I1'. +typeSatisfaction1.ts(12,20): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'I1'. +typeSatisfaction1.ts(13,16): error TS1360: Type '{}' does not satisfy the expected type 'I1'. Property 'a' is missing in type '{}' but required in type 'I1'. -typeSatisfaction.ts(24,23): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'A'. +typeSatisfaction1.ts(24,23): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'A'. -==== typeSatisfaction.ts (3 errors) ==== +==== typeSatisfaction1.ts (3 errors) ==== interface I1 { a: number; } @@ -23,7 +23,7 @@ typeSatisfaction.ts(24,23): error TS2353: Object literal may only specify known ~~~~~~~~~ !!! error TS1360: Type '{}' does not satisfy the expected type 'I1'. !!! error TS1360: Property 'a' is missing in type '{}' but required in type 'I1'. -!!! related TS2728 typeSatisfaction.ts:2:5: 'a' is declared here. +!!! related TS2728 typeSatisfaction1.ts:2:5: 'a' is declared here. const t4: T1 = { a: "a" } satisfies T1; // Ok const t5 = (m => m.substring(0)) satisfies T2; // Ok diff --git a/tests/baselines/reference/typeSatisfaction.js b/tests/baselines/reference/typeSatisfaction1.js similarity index 89% rename from tests/baselines/reference/typeSatisfaction.js rename to tests/baselines/reference/typeSatisfaction1.js index d3f9f88676d20..f39d88fe774bf 100644 --- a/tests/baselines/reference/typeSatisfaction.js +++ b/tests/baselines/reference/typeSatisfaction1.js @@ -1,6 +1,6 @@ -//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction.ts] //// +//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction1.ts] //// -//// [typeSatisfaction.ts] +//// [typeSatisfaction1.ts] interface I1 { a: number; } @@ -27,7 +27,7 @@ let t7 = { a: 'test' } satisfies A; let t8 = { a: 'test', b: 'test' } satisfies A; -//// [typeSatisfaction.js] +//// [typeSatisfaction1.js] var t1 = { a: 1 }; // Ok var t2 = { a: 1, b: 1 }; // Error var t3 = {}; // Error diff --git a/tests/baselines/reference/typeSatisfaction1.symbols b/tests/baselines/reference/typeSatisfaction1.symbols new file mode 100644 index 0000000000000..721c0c66dcd10 --- /dev/null +++ b/tests/baselines/reference/typeSatisfaction1.symbols @@ -0,0 +1,70 @@ +//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction1.ts] //// + +=== typeSatisfaction1.ts === +interface I1 { +>I1 : Symbol(I1, Decl(typeSatisfaction1.ts, 0, 0)) + + a: number; +>a : Symbol(I1.a, Decl(typeSatisfaction1.ts, 0, 14)) +} + +type T1 = { +>T1 : Symbol(T1, Decl(typeSatisfaction1.ts, 2, 1)) + + a: "a" | "b"; +>a : Symbol(a, Decl(typeSatisfaction1.ts, 4, 11)) +} + +type T2 = (x: string) => void; +>T2 : Symbol(T2, Decl(typeSatisfaction1.ts, 6, 1)) +>x : Symbol(x, Decl(typeSatisfaction1.ts, 8, 11)) + +const t1 = { a: 1 } satisfies I1; // Ok +>t1 : Symbol(t1, Decl(typeSatisfaction1.ts, 10, 5)) +>a : Symbol(a, Decl(typeSatisfaction1.ts, 10, 12)) +>I1 : Symbol(I1, Decl(typeSatisfaction1.ts, 0, 0)) + +const t2 = { a: 1, b: 1 } satisfies I1; // Error +>t2 : Symbol(t2, Decl(typeSatisfaction1.ts, 11, 5)) +>a : Symbol(a, Decl(typeSatisfaction1.ts, 11, 12)) +>b : Symbol(b, Decl(typeSatisfaction1.ts, 11, 18)) +>I1 : Symbol(I1, Decl(typeSatisfaction1.ts, 0, 0)) + +const t3 = { } satisfies I1; // Error +>t3 : Symbol(t3, Decl(typeSatisfaction1.ts, 12, 5)) +>I1 : Symbol(I1, Decl(typeSatisfaction1.ts, 0, 0)) + +const t4: T1 = { a: "a" } satisfies T1; // Ok +>t4 : Symbol(t4, Decl(typeSatisfaction1.ts, 14, 5)) +>T1 : Symbol(T1, Decl(typeSatisfaction1.ts, 2, 1)) +>a : Symbol(a, Decl(typeSatisfaction1.ts, 14, 16)) +>T1 : Symbol(T1, Decl(typeSatisfaction1.ts, 2, 1)) + +const t5 = (m => m.substring(0)) satisfies T2; // Ok +>t5 : Symbol(t5, Decl(typeSatisfaction1.ts, 15, 5)) +>m : Symbol(m, Decl(typeSatisfaction1.ts, 15, 12)) +>m.substring : Symbol(String.substring, Decl(lib.es5.d.ts, --, --)) +>m : Symbol(m, Decl(typeSatisfaction1.ts, 15, 12)) +>substring : Symbol(String.substring, Decl(lib.es5.d.ts, --, --)) +>T2 : Symbol(T2, Decl(typeSatisfaction1.ts, 6, 1)) + +const t6 = [1, 2] satisfies [number, number]; +>t6 : Symbol(t6, Decl(typeSatisfaction1.ts, 17, 5)) + +interface A { +>A : Symbol(A, Decl(typeSatisfaction1.ts, 17, 45)) + + a: string +>a : Symbol(A.a, Decl(typeSatisfaction1.ts, 19, 13)) +} +let t7 = { a: 'test' } satisfies A; +>t7 : Symbol(t7, Decl(typeSatisfaction1.ts, 22, 3)) +>a : Symbol(a, Decl(typeSatisfaction1.ts, 22, 10)) +>A : Symbol(A, Decl(typeSatisfaction1.ts, 17, 45)) + +let t8 = { a: 'test', b: 'test' } satisfies A; +>t8 : Symbol(t8, Decl(typeSatisfaction1.ts, 23, 3)) +>a : Symbol(a, Decl(typeSatisfaction1.ts, 23, 10)) +>b : Symbol(b, Decl(typeSatisfaction1.ts, 23, 21)) +>A : Symbol(A, Decl(typeSatisfaction1.ts, 17, 45)) + diff --git a/tests/baselines/reference/typeSatisfaction.types b/tests/baselines/reference/typeSatisfaction1.types similarity index 94% rename from tests/baselines/reference/typeSatisfaction.types rename to tests/baselines/reference/typeSatisfaction1.types index 688625f272419..8913e2acddcf1 100644 --- a/tests/baselines/reference/typeSatisfaction.types +++ b/tests/baselines/reference/typeSatisfaction1.types @@ -1,6 +1,6 @@ -//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction.ts] //// +//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction1.ts] //// -=== typeSatisfaction.ts === +=== typeSatisfaction1.ts === interface I1 { a: number; >a : number diff --git a/tests/baselines/reference/typeSatisfaction2.errors.txt b/tests/baselines/reference/typeSatisfaction2.errors.txt new file mode 100644 index 0000000000000..0934081441974 --- /dev/null +++ b/tests/baselines/reference/typeSatisfaction2.errors.txt @@ -0,0 +1,63 @@ +typeSatisfaction2.ts(5,36): error TS1360: Type '() => void' does not satisfy the expected type '() => number'. + Type 'void' is not assignable to type 'number'. +typeSatisfaction2.ts(18,13): error TS1360: Type '(a: boolean, b: boolean) => number' does not satisfy the expected type '(a: number, b: number) => number'. + Types of parameters 'a' and 'a' are incompatible. + Type 'number' is not assignable to type 'boolean'. +typeSatisfaction2.ts(22,13): error TS1360: Type '(a: number, b: boolean) => number' does not satisfy the expected type 'T2'. + Types of parameters 'b' and 'b' are incompatible. + Type 'number' is not assignable to type 'boolean'. +typeSatisfaction2.ts(26,13): error TS1360: Type '(a: number, b: number) => string' does not satisfy the expected type '(a: number, b: number) => number'. + Type 'string' is not assignable to type 'number'. +typeSatisfaction2.ts(30,13): error TS1360: Type '(a: number, b: number) => string' does not satisfy the expected type 'T2'. + Type 'string' is not assignable to type 'number'. + + +==== typeSatisfaction2.ts (5 errors) ==== + export type T1 = () => void; + export type T2 = (a: number, b: number) => number; + + export function f1() { } satisfies () => void; + export function f2() { } satisfies () => number; + ~~~~~~~~~~~~ +!!! error TS1360: Type '() => void' does not satisfy the expected type '() => number'. +!!! error TS1360: Type 'void' is not assignable to type 'number'. + export function f3() { } satisfies T1; + + export function f4(a: number, b: number) { + return 1; + } satisfies (a: number, b: number) => number; + + export function f5(a: number, b: number) { + return 1; + } satisfies T2; + + export function f6(a: boolean, b: boolean) { + return 1; + } satisfies (a: number, b: number) => number; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1360: Type '(a: boolean, b: boolean) => number' does not satisfy the expected type '(a: number, b: number) => number'. +!!! error TS1360: Types of parameters 'a' and 'a' are incompatible. +!!! error TS1360: Type 'number' is not assignable to type 'boolean'. + + export function f7(a: number, b: boolean) { + return 1; + } satisfies T2; + ~~ +!!! error TS1360: Type '(a: number, b: boolean) => number' does not satisfy the expected type 'T2'. +!!! error TS1360: Types of parameters 'b' and 'b' are incompatible. +!!! error TS1360: Type 'number' is not assignable to type 'boolean'. + + export function f8(a: number, b: number) { + return ""; + } satisfies (a: number, b: number) => number; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1360: Type '(a: number, b: number) => string' does not satisfy the expected type '(a: number, b: number) => number'. +!!! error TS1360: Type 'string' is not assignable to type 'number'. + + export function f9(a: number, b: number) { + return ""; + } satisfies T2; + ~~ +!!! error TS1360: Type '(a: number, b: number) => string' does not satisfy the expected type 'T2'. +!!! error TS1360: Type 'string' is not assignable to type 'number'. + \ No newline at end of file diff --git a/tests/baselines/reference/typeSatisfaction2.js b/tests/baselines/reference/typeSatisfaction2.js new file mode 100644 index 0000000000000..584b891a568e5 --- /dev/null +++ b/tests/baselines/reference/typeSatisfaction2.js @@ -0,0 +1,77 @@ +//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction2.ts] //// + +//// [typeSatisfaction2.ts] +export type T1 = () => void; +export type T2 = (a: number, b: number) => number; + +export function f1() { } satisfies () => void; +export function f2() { } satisfies () => number; +export function f3() { } satisfies T1; + +export function f4(a: number, b: number) { + return 1; +} satisfies (a: number, b: number) => number; + +export function f5(a: number, b: number) { + return 1; +} satisfies T2; + +export function f6(a: boolean, b: boolean) { + return 1; +} satisfies (a: number, b: number) => number; + +export function f7(a: number, b: boolean) { + return 1; +} satisfies T2; + +export function f8(a: number, b: number) { + return ""; +} satisfies (a: number, b: number) => number; + +export function f9(a: number, b: number) { + return ""; +} satisfies T2; + + +//// [typeSatisfaction2.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.f1 = f1; +exports.f2 = f2; +exports.f3 = f3; +exports.f4 = f4; +exports.f5 = f5; +exports.f6 = f6; +exports.f7 = f7; +exports.f8 = f8; +exports.f9 = f9; +function f1() { } +; +function f2() { } +; +function f3() { } +; +function f4(a, b) { + return 1; +} +; +function f5(a, b) { + return 1; +} +; +function f6(a, b) { + return 1; +} +; +function f7(a, b) { + return 1; +} +; +function f8(a, b) { + return ""; +} +; +function f9(a, b) { + return ""; +} +; diff --git a/tests/baselines/reference/typeSatisfaction2.symbols b/tests/baselines/reference/typeSatisfaction2.symbols new file mode 100644 index 0000000000000..76198c00990e0 --- /dev/null +++ b/tests/baselines/reference/typeSatisfaction2.symbols @@ -0,0 +1,78 @@ +//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction2.ts] //// + +=== typeSatisfaction2.ts === +export type T1 = () => void; +>T1 : Symbol(T1, Decl(typeSatisfaction2.ts, 0, 0)) + +export type T2 = (a: number, b: number) => number; +>T2 : Symbol(T2, Decl(typeSatisfaction2.ts, 0, 28)) +>a : Symbol(a, Decl(typeSatisfaction2.ts, 1, 18)) +>b : Symbol(b, Decl(typeSatisfaction2.ts, 1, 28)) + +export function f1() { } satisfies () => void; +>f1 : Symbol(f1, Decl(typeSatisfaction2.ts, 1, 50)) + +export function f2() { } satisfies () => number; +>f2 : Symbol(f2, Decl(typeSatisfaction2.ts, 3, 46)) + +export function f3() { } satisfies T1; +>f3 : Symbol(f3, Decl(typeSatisfaction2.ts, 4, 48)) +>T1 : Symbol(T1, Decl(typeSatisfaction2.ts, 0, 0)) + +export function f4(a: number, b: number) { +>f4 : Symbol(f4, Decl(typeSatisfaction2.ts, 5, 38)) +>a : Symbol(a, Decl(typeSatisfaction2.ts, 7, 19)) +>b : Symbol(b, Decl(typeSatisfaction2.ts, 7, 29)) + + return 1; +} satisfies (a: number, b: number) => number; +>a : Symbol(a, Decl(typeSatisfaction2.ts, 9, 13)) +>b : Symbol(b, Decl(typeSatisfaction2.ts, 9, 23)) + +export function f5(a: number, b: number) { +>f5 : Symbol(f5, Decl(typeSatisfaction2.ts, 9, 45)) +>a : Symbol(a, Decl(typeSatisfaction2.ts, 11, 19)) +>b : Symbol(b, Decl(typeSatisfaction2.ts, 11, 29)) + + return 1; +} satisfies T2; +>T2 : Symbol(T2, Decl(typeSatisfaction2.ts, 0, 28)) + +export function f6(a: boolean, b: boolean) { +>f6 : Symbol(f6, Decl(typeSatisfaction2.ts, 13, 15)) +>a : Symbol(a, Decl(typeSatisfaction2.ts, 15, 19)) +>b : Symbol(b, Decl(typeSatisfaction2.ts, 15, 30)) + + return 1; +} satisfies (a: number, b: number) => number; +>a : Symbol(a, Decl(typeSatisfaction2.ts, 17, 13)) +>b : Symbol(b, Decl(typeSatisfaction2.ts, 17, 23)) + +export function f7(a: number, b: boolean) { +>f7 : Symbol(f7, Decl(typeSatisfaction2.ts, 17, 45)) +>a : Symbol(a, Decl(typeSatisfaction2.ts, 19, 19)) +>b : Symbol(b, Decl(typeSatisfaction2.ts, 19, 29)) + + return 1; +} satisfies T2; +>T2 : Symbol(T2, Decl(typeSatisfaction2.ts, 0, 28)) + +export function f8(a: number, b: number) { +>f8 : Symbol(f8, Decl(typeSatisfaction2.ts, 21, 15)) +>a : Symbol(a, Decl(typeSatisfaction2.ts, 23, 19)) +>b : Symbol(b, Decl(typeSatisfaction2.ts, 23, 29)) + + return ""; +} satisfies (a: number, b: number) => number; +>a : Symbol(a, Decl(typeSatisfaction2.ts, 25, 13)) +>b : Symbol(b, Decl(typeSatisfaction2.ts, 25, 23)) + +export function f9(a: number, b: number) { +>f9 : Symbol(f9, Decl(typeSatisfaction2.ts, 25, 45)) +>a : Symbol(a, Decl(typeSatisfaction2.ts, 27, 19)) +>b : Symbol(b, Decl(typeSatisfaction2.ts, 27, 29)) + + return ""; +} satisfies T2; +>T2 : Symbol(T2, Decl(typeSatisfaction2.ts, 0, 28)) + diff --git a/tests/baselines/reference/typeSatisfaction2.types b/tests/baselines/reference/typeSatisfaction2.types new file mode 100644 index 0000000000000..ee700e9a1a790 --- /dev/null +++ b/tests/baselines/reference/typeSatisfaction2.types @@ -0,0 +1,123 @@ +//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction2.ts] //// + +=== typeSatisfaction2.ts === +export type T1 = () => void; +>T1 : T1 +> : ^^ + +export type T2 = (a: number, b: number) => number; +>T2 : T2 +> : ^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ + +export function f1() { } satisfies () => void; +>f1 : () => void +> : ^^^^^^^^^^ + +export function f2() { } satisfies () => number; +>f2 : () => void +> : ^^^^^^^^^^ + +export function f3() { } satisfies T1; +>f3 : () => void +> : ^^^^^^^^^^ + +export function f4(a: number, b: number) { +>f4 : (a: number, b: number) => number +> : ^^^^ ^^^^^ ^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ + + return 1; +>1 : 1 +> : ^ + +} satisfies (a: number, b: number) => number; +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ + +export function f5(a: number, b: number) { +>f5 : (a: number, b: number) => number +> : ^^^^ ^^^^^ ^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ + + return 1; +>1 : 1 +> : ^ + +} satisfies T2; + +export function f6(a: boolean, b: boolean) { +>f6 : (a: boolean, b: boolean) => number +> : ^^^^ ^^^^^ ^^^^^^^^^^^ +>a : boolean +> : ^^^^^^^ +>b : boolean +> : ^^^^^^^ + + return 1; +>1 : 1 +> : ^ + +} satisfies (a: number, b: number) => number; +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ + +export function f7(a: number, b: boolean) { +>f7 : (a: number, b: boolean) => number +> : ^^^^ ^^^^^ ^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>b : boolean +> : ^^^^^^^ + + return 1; +>1 : 1 +> : ^ + +} satisfies T2; + +export function f8(a: number, b: number) { +>f8 : (a: number, b: number) => string +> : ^^^^ ^^^^^ ^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ + + return ""; +>"" : "" +> : ^^ + +} satisfies (a: number, b: number) => number; +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ + +export function f9(a: number, b: number) { +>f9 : (a: number, b: number) => string +> : ^^^^ ^^^^^ ^^^^^^^^^^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ + + return ""; +>"" : "" +> : ^^ + +} satisfies T2; + diff --git a/tests/baselines/reference/typeSatisfaction3.errors.txt b/tests/baselines/reference/typeSatisfaction3.errors.txt new file mode 100644 index 0000000000000..4f0c68c2adf39 --- /dev/null +++ b/tests/baselines/reference/typeSatisfaction3.errors.txt @@ -0,0 +1,22 @@ +typeSatisfaction3.ts(7,13): error TS1360: Type 'C1' does not satisfy the expected type 'T1'. + Types of property 'p' are incompatible. + Type 'number' is not assignable to type 'string'. + + +==== typeSatisfaction3.ts (1 errors) ==== + type T1 = { + p: string; + } + + class C1 { + p: number; + } satisfies T1; + ~~ +!!! error TS1360: Type 'C1' does not satisfy the expected type 'T1'. +!!! error TS1360: Types of property 'p' are incompatible. +!!! error TS1360: Type 'number' is not assignable to type 'string'. + + class C2 { + p: string; + } satisfies T1; + \ No newline at end of file diff --git a/tests/baselines/reference/typeSatisfaction3.js b/tests/baselines/reference/typeSatisfaction3.js new file mode 100644 index 0000000000000..9738eb5739f32 --- /dev/null +++ b/tests/baselines/reference/typeSatisfaction3.js @@ -0,0 +1,29 @@ +//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction3.ts] //// + +//// [typeSatisfaction3.ts] +type T1 = { + p: string; +} + +class C1 { + p: number; +} satisfies T1; + +class C2 { + p: string; +} satisfies T1; + + +//// [typeSatisfaction3.js] +var C1 = /** @class */ (function () { + function C1() { + } + return C1; +}()); +; +var C2 = /** @class */ (function () { + function C2() { + } + return C2; +}()); +; diff --git a/tests/baselines/reference/typeSatisfaction3.symbols b/tests/baselines/reference/typeSatisfaction3.symbols new file mode 100644 index 0000000000000..fe7084941d5fb --- /dev/null +++ b/tests/baselines/reference/typeSatisfaction3.symbols @@ -0,0 +1,28 @@ +//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction3.ts] //// + +=== typeSatisfaction3.ts === +type T1 = { +>T1 : Symbol(T1, Decl(typeSatisfaction3.ts, 0, 0)) + + p: string; +>p : Symbol(p, Decl(typeSatisfaction3.ts, 0, 11)) +} + +class C1 { +>C1 : Symbol(C1, Decl(typeSatisfaction3.ts, 2, 1)) + + p: number; +>p : Symbol(C1.p, Decl(typeSatisfaction3.ts, 4, 10)) + +} satisfies T1; +>T1 : Symbol(T1, Decl(typeSatisfaction3.ts, 0, 0)) + +class C2 { +>C2 : Symbol(C2, Decl(typeSatisfaction3.ts, 6, 15)) + + p: string; +>p : Symbol(C2.p, Decl(typeSatisfaction3.ts, 8, 10)) + +} satisfies T1; +>T1 : Symbol(T1, Decl(typeSatisfaction3.ts, 0, 0)) + diff --git a/tests/baselines/reference/typeSatisfaction3.types b/tests/baselines/reference/typeSatisfaction3.types new file mode 100644 index 0000000000000..3ee455fc99fc6 --- /dev/null +++ b/tests/baselines/reference/typeSatisfaction3.types @@ -0,0 +1,32 @@ +//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction3.ts] //// + +=== typeSatisfaction3.ts === +type T1 = { +>T1 : T1 +> : ^^ + + p: string; +>p : string +> : ^^^^^^ +} + +class C1 { +>C1 : C1 +> : ^^ + + p: number; +>p : number +> : ^^^^^^ + +} satisfies T1; + +class C2 { +>C2 : C2 +> : ^^ + + p: string; +>p : string +> : ^^^^^^ + +} satisfies T1; + diff --git a/tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction.ts b/tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction1.ts similarity index 100% rename from tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction.ts rename to tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction1.ts diff --git a/tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction2.ts b/tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction2.ts new file mode 100644 index 0000000000000..cf7e153fdb4e1 --- /dev/null +++ b/tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction2.ts @@ -0,0 +1,30 @@ +export type T1 = () => void; +export type T2 = (a: number, b: number) => number; + +export function f1() { } satisfies () => void; +export function f2() { } satisfies () => number; +export function f3() { } satisfies T1; + +export function f4(a: number, b: number) { + return 1; +} satisfies (a: number, b: number) => number; + +export function f5(a: number, b: number) { + return 1; +} satisfies T2; + +export function f6(a: boolean, b: boolean) { + return 1; +} satisfies (a: number, b: number) => number; + +export function f7(a: number, b: boolean) { + return 1; +} satisfies T2; + +export function f8(a: number, b: number) { + return ""; +} satisfies (a: number, b: number) => number; + +export function f9(a: number, b: number) { + return ""; +} satisfies T2; diff --git a/tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction3.ts b/tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction3.ts new file mode 100644 index 0000000000000..c855437fdd266 --- /dev/null +++ b/tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction3.ts @@ -0,0 +1,11 @@ +type T1 = { + p: string; +} + +class C1 { + p: number; +} satisfies T1; + +class C2 { + p: string; +} satisfies T1; diff --git a/tests/cases/fourslash/completionSatisfiesKeyword.ts b/tests/cases/fourslash/completionSatisfiesKeyword.ts index c44ca016c3f6f..4be27e52e361c 100644 --- a/tests/cases/fourslash/completionSatisfiesKeyword.ts +++ b/tests/cases/fourslash/completionSatisfiesKeyword.ts @@ -3,9 +3,11 @@ ////const x = { a: 1 } /*1*/ ////function foo() { //// const x = { a: 1 } /*2*/ -////} +////} /*3*/ +//// +////class C {} /*4*/ verify.completions({ - marker: ["1", "2"], + marker: ["1", "2", "3", "4"], includes: [{ name: "satisfies", sortText: completion.SortText.GlobalsOrKeywords }] }); diff --git a/tests/cases/fourslash/formatSatisfiesClause.ts b/tests/cases/fourslash/formatSatisfiesClause.ts new file mode 100644 index 0000000000000..219d189882f7a --- /dev/null +++ b/tests/cases/fourslash/formatSatisfiesClause.ts @@ -0,0 +1,28 @@ +/// + +////type T1 = { +//// p: string; +////} +//// +////function f1() { } satisfies () => {} +////function f2() { }satisfies () => {} +////function f3() { } satisfies () => {} +//// +////class C1 { } satisfies T1 +////class C2 { }satisfies T1 +////class C3 { } satisfies T1 + +format.document(); +verify.currentFileContentIs( +`type T1 = { + p: string; +} + +function f1() { } satisfies () => {} +function f2() { } satisfies () => {} +function f3() { } satisfies () => {} + +class C1 { } satisfies T1 +class C2 { } satisfies T1 +class C3 { } satisfies T1` +);