diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 356ddc2a28e1a..49482f45f999a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3468,7 +3468,7 @@ namespace ts { } const typeParameterNode = typeParameterToDeclarationWithConstraint(getTypeParameterFromMappedType(type), context, appropriateConstraintTypeNode); const templateTypeNode = typeToTypeNodeHelper(getTemplateTypeFromMappedType(type), context); - const mappedTypeNode = createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode); + const mappedTypeNode = createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode, type.declaration.isExact); context.approximateLength += 10; return setEmitFlags(mappedTypeNode, EmitFlags.SingleLine); } @@ -3552,7 +3552,7 @@ namespace ts { if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) { if (!resolved.callSignatures.length && !resolved.constructSignatures.length) { context.approximateLength += 2; - return setEmitFlags(createTypeLiteralNode(/*members*/ undefined), EmitFlags.SingleLine); + return setEmitFlags(createTypeLiteralNode(/*members*/ undefined, !!(type.objectFlags & ObjectFlags.Exact)), EmitFlags.SingleLine); } if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { @@ -3573,7 +3573,7 @@ namespace ts { context.flags |= NodeBuilderFlags.InObjectTypeLiteral; const members = createTypeNodesFromResolvedType(resolved); context.flags = savedFlags; - const typeLiteralNode = createTypeLiteralNode(members); + const typeLiteralNode = createTypeLiteralNode(members, !!(type.objectFlags & ObjectFlags.Exact)); context.approximateLength += 2; return setEmitFlags(typeLiteralNode, (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine); } @@ -9762,7 +9762,11 @@ namespace ts { function getTypeFromMappedTypeNode(node: MappedTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - const type = createObjectType(ObjectFlags.Mapped, node.symbol); + let flags = ObjectFlags.Mapped; + if (node.isExact) { + flags |= ObjectFlags.Exact; + } + const type = createObjectType(flags, node.symbol); type.declaration = node; type.aliasSymbol = getAliasSymbolForTypeNode(node); type.aliasTypeArguments = getTypeArgumentsForAliasSymbol(type.aliasSymbol); @@ -9994,7 +9998,11 @@ namespace ts { links.resolvedType = emptyTypeLiteralType; } else { - let type = createObjectType(ObjectFlags.Anonymous, node.symbol); + let flags = ObjectFlags.Anonymous; + if (isTypeLiteralNode(node) && node.isExact) { + flags |= ObjectFlags.Exact; + } + let type = createObjectType(flags, node.symbol); type.aliasSymbol = aliasSymbol; type.aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); if (isJSDocTypeLiteral(node) && node.isArrayType) { @@ -11527,6 +11535,7 @@ namespace ts { let expandingFlags = ExpandingFlags.None; let overflow = false; let suppressNextError = false; + let inExactContext = false; Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking"); @@ -11662,6 +11671,11 @@ namespace ts { target = getSimplifiedType(target); } + // Are we in a context that uses exact types? If so we + // disable excess property checking and just use exact + // type rules. + inExactContext = inExactContext || someType(target, t => (getObjectFlags(t) & ObjectFlags.Exact) !== 0); + // Try to see if we're relating something like `Foo` -> `Bar | null | undefined`. // If so, reporting the `null` and `undefined` in the type is hardly useful. // First, see if we're even relating an object type to a union. @@ -11689,8 +11703,19 @@ namespace ts { if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; + if ((getObjectFlags(target) & ObjectFlags.Exact) && !(getObjectFlags(source) & (ObjectFlags.Exact | ObjectFlags.FreshLiteral))) { + if (reportErrors) { + reportRelationError(Diagnostics.Non_exact_types_are_not_assignable_to_exact_types, source, target); + } + return Ternary.False; + } + const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); - if (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral) { + + // if we are in an exact context, we should not drop freshness. + // we should only check excess if this is a literal + const shouldCheckExcess = !inExactContext || (getObjectFlags(target) & ObjectFlags.Exact); + if (shouldCheckExcess && isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral) { const discriminantType = target.flags & TypeFlags.Union ? findMatchingDiscriminantType(source, target as UnionType) : undefined; if (hasExcessProperties(source, target, discriminantType, reportErrors)) { if (reportErrors) { @@ -11702,7 +11727,10 @@ namespace ts { // and intersection types are further deconstructed on the target side, we don't want to // make the check again (as it might fail for a partial target type). Therefore we obtain // the regular source type and proceed with that. - if (isUnionOrIntersectionTypeWithoutNullableConstituents(target) && !discriminantType) { + // + // Note that if we are in an exact context we do not drop freshness incase we encounter a nested + // exact type and we need to know the source is a literal. + if (!inExactContext && isUnionOrIntersectionTypeWithoutNullableConstituents(target) && !discriminantType) { source = getRegularTypeOfObjectLiteral(source); } } @@ -11881,7 +11909,9 @@ namespace ts { symbolToString(prop), typeToString(errorTarget), suggestion); } else { - reportError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, + reportError(getObjectFlags(target) & ObjectFlags.Exact ? + Diagnostics.Object_literal_may_only_specify_known_properties_when_assigned_to_exact_type_and_0_does_not_exist_in_type_1 : + Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, symbolToString(prop), typeToString(errorTarget)); } } @@ -12457,6 +12487,18 @@ namespace ts { getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target)); if (modifiersRelated) { let result: Ternary; + if (getObjectFlags(target) & ObjectFlags.Exact) { + // TODO: Not sure if identical is right here and need Better errors here. + if (isTypeIdenticalTo(getConstraintTypeFromMappedType(target), getConstraintTypeFromMappedType(source))) { + const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]); + return isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), reportErrors); + } + if (reportErrors) { + // Invariant. source must be exact. + reportError(Diagnostics.Exact_mapped_types_0_and_1_do_not_have_identical_key_constraints, typeToString(source), typeToString(target)); + } + return Ternary.False; + } if (result = isRelatedTo(getConstraintTypeFromMappedType(target), getConstraintTypeFromMappedType(source), reportErrors)) { const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]); return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), reportErrors); @@ -12494,13 +12536,15 @@ namespace ts { } return Ternary.False; } - if (isObjectLiteralType(target)) { + if (isObjectLiteralType(target) || (getObjectFlags(target) & ObjectFlags.Exact)) { for (const sourceProp of getPropertiesOfType(source)) { if (!getPropertyOfObjectType(target, sourceProp.escapedName)) { const sourceType = getTypeOfSymbol(sourceProp); if (!(sourceType === undefinedType || sourceType === undefinedWideningType)) { if (reportErrors) { - reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(sourceProp), typeToString(target)); + reportError(getObjectFlags(target) & ObjectFlags.Exact ? + Diagnostics.Exact_types_may_only_include_specified_properties_and_0_does_not_exist_on_type_1 : + Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(sourceProp), typeToString(target)); } return Ternary.False; } @@ -15102,6 +15146,10 @@ namespace ts { return type.flags & TypeFlags.Union ? every((type).types, f) : f(type); } + function someType(type: Type, f: (t: Type) => boolean): boolean { + return type.flags & TypeFlags.UnionOrIntersection ? some((type).types, f) : f(type); + } + function filterType(type: Type, f: (t: Type) => boolean): Type { if (type.flags & TypeFlags.Union) { const types = (type).types; @@ -21797,6 +21845,11 @@ namespace ts { error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference); return booleanType; } + const expression = (expr).expression; + const type = getTypeOfExpression(expression); + if (someType(type, t => (getObjectFlags(t) & ObjectFlags.Exact) !== 0)) { + error(expression, Diagnostics.Properties_on_exact_types_cannot_be_deleted); + } const links = getNodeLinks(expr); const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol); if (symbol && isReadonlySymbol(symbol)) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 2cbf5784d0786..7c06574305441 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4137,7 +4137,26 @@ "category": "Error", "code": 7051 }, - + "Non-exact types are not assignable to exact types.": { + "category": "Error", + "code": 7052 + }, + "Properties on exact types cannot be deleted.": { + "category": "Error", + "code": 7053 + }, + "Exact mapped types {0} and {1} do not have identical key constraints.": { + "category": "Error", + "code": 7054 + }, + "Object literal may only specify known properties when assigned to exact type, and '{0}' does not exist in type '{1}'.": { + "category": "Error", + "code": 7055 + }, + "Exact types may only include specified properties, and '{0}' does not exist on type '{1}'.": { + "category": "Error", + "code": 7056 + }, "You cannot rename this element.": { "category": "Error", "code": 8000 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 9c09ed79a7780..fcf18b598aa27 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1451,8 +1451,14 @@ namespace ts { function emitTypeLiteral(node: TypeLiteralNode) { writePunctuation("{"); + if (node.isExact) { + writePunctuation("|"); + } const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers; emitList(node, node.members, flags | ListFormat.NoSpaceIfEmpty); + if (node.isExact) { + writePunctuation("|"); + } writePunctuation("}"); } @@ -1534,6 +1540,9 @@ namespace ts { function emitMappedType(node: MappedTypeNode) { const emitFlags = getEmitFlags(node); writePunctuation("{"); + if (node.isExact) { + writePunctuation("|"); + } if (emitFlags & EmitFlags.SingleLine) { writeSpace(); } @@ -1571,6 +1580,9 @@ namespace ts { writeLine(); decreaseIndent(); } + if (node.isExact) { + writePunctuation("|"); + } writePunctuation("}"); } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index ec19d2c906c12..3e1f81d054b96 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -723,15 +723,16 @@ namespace ts { : node; } - export function createTypeLiteralNode(members: ReadonlyArray | undefined) { + export function createTypeLiteralNode(members: ReadonlyArray | undefined, isExact = false) { const node = createSynthesizedNode(SyntaxKind.TypeLiteral) as TypeLiteralNode; + node.isExact = isExact; node.members = createNodeArray(members); return node; } export function updateTypeLiteralNode(node: TypeLiteralNode, members: NodeArray) { return node.members !== members - ? updateNode(createTypeLiteralNode(members), node) + ? updateNode(createTypeLiteralNode(members, node.isExact), node) : node; } @@ -902,8 +903,9 @@ namespace ts { : node; } - export function createMappedTypeNode(readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode { + export function createMappedTypeNode(readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, isExact: boolean): MappedTypeNode { const node = createSynthesizedNode(SyntaxKind.MappedType) as MappedTypeNode; + node.isExact = isExact; node.readonlyToken = readonlyToken; node.typeParameter = typeParameter; node.questionToken = questionToken; @@ -911,12 +913,12 @@ namespace ts { return node; } - export function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode { + export function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, isExact: boolean): MappedTypeNode { return node.readonlyToken !== readonlyToken || node.typeParameter !== typeParameter || node.questionToken !== questionToken || node.type !== type - ? updateNode(createMappedTypeNode(readonlyToken, typeParameter, questionToken, type), node) + ? updateNode(createMappedTypeNode(readonlyToken, typeParameter, questionToken, type, isExact), node) : node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f976f77ea985a..80af0e806d08f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1601,9 +1601,10 @@ namespace ts { } switch (kind) { + case ParsingContext.TypeMembers: + return token() === SyntaxKind.BarToken || token() === SyntaxKind.CloseBraceToken; case ParsingContext.BlockStatements: case ParsingContext.SwitchClauses: - case ParsingContext.TypeMembers: case ParsingContext.ClassMembers: case ParsingContext.EnumMembers: case ParsingContext.ObjectLiteralMembers: @@ -2746,14 +2747,31 @@ namespace ts { function parseTypeLiteral(): TypeLiteralNode { const node = createNode(SyntaxKind.TypeLiteral); - node.members = parseObjectTypeMembers(); - return finishNode(node); + if (parseExpected(SyntaxKind.OpenBraceToken)) { + const isExact = parseOptional(SyntaxKind.BarToken); + node.isExact = isExact; + node.members = parseList(ParsingContext.TypeMembers, parseTypeMember); + if (isExact) { + parseExpected(SyntaxKind.BarToken); + } + parseExpected(SyntaxKind.CloseBraceToken); + return finishNode(node); + } + else { + const node = createNode(SyntaxKind.TypeLiteral); + node.members = createMissingList(); + return finishNode(node); + } } function parseObjectTypeMembers(): NodeArray { let members: NodeArray; if (parseExpected(SyntaxKind.OpenBraceToken)) { + const isExact = parseOptional(SyntaxKind.BarToken); members = parseList(ParsingContext.TypeMembers, parseTypeMember); + if (isExact) { + parseExpected(SyntaxKind.BarToken); + } parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -2765,6 +2783,7 @@ namespace ts { function isStartOfMappedType() { nextToken(); + parseOptional(SyntaxKind.BarToken); if (token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { return nextToken() === SyntaxKind.ReadonlyKeyword; } @@ -2785,6 +2804,8 @@ namespace ts { function parseMappedType() { const node = createNode(SyntaxKind.MappedType); parseExpected(SyntaxKind.OpenBraceToken); + const isExact = parseOptional(SyntaxKind.BarToken); + node.isExact = isExact; if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { node.readonlyToken = parseTokenNode(); if (node.readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) { @@ -2802,6 +2823,9 @@ namespace ts { } node.type = parseTypeAnnotation(); parseSemicolon(); + if (isExact) { + parseExpected(SyntaxKind.BarToken); + } parseExpected(SyntaxKind.CloseBraceToken); return finishNode(node); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 495465f70326c..64958077d0456 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1178,6 +1178,7 @@ namespace ts { // A TypeLiteral is the declaration node for an anonymous symbol. export interface TypeLiteralNode extends TypeNode, Declaration { kind: SyntaxKind.TypeLiteral; + isExact: boolean; members: NodeArray; } @@ -1253,6 +1254,7 @@ namespace ts { readonlyToken?: ReadonlyToken | PlusToken | MinusToken; typeParameter: TypeParameterDeclaration; questionToken?: QuestionToken | PlusToken | MinusToken; + isExact: boolean; type?: TypeNode; } @@ -3976,6 +3978,7 @@ namespace ts { MarkerType = 1 << 13, // Marker type used for variance probing JSLiteral = 1 << 14, // Object type declared in JS - disables errors on read/write of nonexisting members FreshLiteral = 1 << 15, // Fresh object literal + Exact = 1 << 16, // Exact object type - disables width subtyping ClassOrInterface = Class | Interface } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 18b7c3f4a746a..9651e024f76ab 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -428,7 +428,7 @@ namespace ts { visitNode((node).readonlyToken, tokenVisitor, isToken), visitNode((node).typeParameter, visitor, isTypeParameterDeclaration), visitNode((node).questionToken, tokenVisitor, isToken), - visitNode((node).type, visitor, isTypeNode)); + visitNode((node).type, visitor, isTypeNode), (node).isExact); case SyntaxKind.LiteralType: return updateLiteralTypeNode(node, diff --git a/src/services/codefixes/convertToMappedObjectType.ts b/src/services/codefixes/convertToMappedObjectType.ts index 0d79d6363c0ae..878e4fdd4c5e2 100644 --- a/src/services/codefixes/convertToMappedObjectType.ts +++ b/src/services/codefixes/convertToMappedObjectType.ts @@ -45,7 +45,8 @@ namespace ts.codefix { hasReadonlyModifier(indexSignature) ? createModifier(SyntaxKind.ReadonlyKeyword) : undefined, mappedTypeParameter, indexSignature.questionToken, - indexSignature.type); + indexSignature.type, + /*isExact*/ false); const intersectionType = createIntersectionTypeNode([ ...getAllSuperTypeNodes(container), mappedIntersectionType, diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.callSignatureInRecordType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.callSignatureInRecordType.json index 6c00c3a8912cc..f1adeb3403d40 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.callSignatureInRecordType.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.callSignatureInRecordType.json @@ -3,6 +3,7 @@ "pos": 1, "end": 13, "flags": "JSDoc", + "isExact": false, "members": { "0": { "kind": "CallSignature", diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.methodInRecordType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.methodInRecordType.json index 3d94654aa1932..d340e646bfec0 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.methodInRecordType.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.methodInRecordType.json @@ -3,6 +3,7 @@ "pos": 1, "end": 16, "flags": "JSDoc", + "isExact": false, "members": { "0": { "kind": "MethodSignature", diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json index eb669992ca287..607d02c83992a 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json @@ -3,6 +3,7 @@ "pos": 1, "end": 3, "flags": "JSDoc", + "isExact": false, "members": { "length": 0, "pos": 2, diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json index c1a48a6c3853a..e73e40f3453e7 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json @@ -3,6 +3,7 @@ "pos": 1, "end": 6, "flags": "JSDoc", + "isExact": false, "members": { "0": { "kind": "PropertySignature", diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json index b21dae3e77cb0..25d64df2188d1 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json @@ -3,6 +3,7 @@ "pos": 1, "end": 14, "flags": "JSDoc", + "isExact": false, "members": { "0": { "kind": "PropertySignature", diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json index a3c37d1efabbd..da36cc396d968 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json @@ -3,6 +3,7 @@ "pos": 1, "end": 11, "flags": "JSDoc", + "isExact": false, "members": { "0": { "kind": "PropertySignature", diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json index 30949ee9ab4a1..d547f94932837 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json @@ -3,6 +3,7 @@ "pos": 1, "end": 19, "flags": "JSDoc", + "isExact": false, "members": { "0": { "kind": "PropertySignature", diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json index 396645856a83f..c7500a076a60b 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json @@ -3,6 +3,7 @@ "pos": 1, "end": 19, "flags": "JSDoc", + "isExact": false, "members": { "0": { "kind": "PropertySignature", diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json index c8eba7da464ff..fd5c01eff0c3e 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json @@ -3,6 +3,7 @@ "pos": 1, "end": 27, "flags": "JSDoc", + "isExact": false, "members": { "0": { "kind": "PropertySignature", diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json index c851d76a6fe1d..75d4c68dc0a80 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json @@ -3,6 +3,7 @@ "pos": 1, "end": 11, "flags": "JSDoc", + "isExact": false, "members": { "0": { "kind": "PropertySignature", diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.trailingCommaInRecordType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.trailingCommaInRecordType.json index 70aff3b729882..bb6143388cf08 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.trailingCommaInRecordType.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.trailingCommaInRecordType.json @@ -3,6 +3,7 @@ "pos": 1, "end": 5, "flags": "JSDoc", + "isExact": false, "members": { "0": { "kind": "PropertySignature", diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 2b78178587e56..b6ab733173594 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -770,6 +770,7 @@ declare namespace ts { } interface TypeLiteralNode extends TypeNode, Declaration { kind: SyntaxKind.TypeLiteral; + isExact: boolean; members: NodeArray; } interface ArrayTypeNode extends TypeNode { @@ -827,6 +828,7 @@ declare namespace ts { readonlyToken?: ReadonlyToken | PlusToken | MinusToken; typeParameter: TypeParameterDeclaration; questionToken?: QuestionToken | PlusToken | MinusToken; + isExact: boolean; type?: TypeNode; } interface LiteralTypeNode extends TypeNode { @@ -2243,6 +2245,7 @@ declare namespace ts { MarkerType = 8192, JSLiteral = 16384, FreshLiteral = 32768, + Exact = 65536, ClassOrInterface = 3 } interface ObjectType extends Type { @@ -3729,7 +3732,7 @@ declare namespace ts { function updateConstructorTypeNode(node: ConstructorTypeNode, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined): ConstructorTypeNode; function createTypeQueryNode(exprName: EntityName): TypeQueryNode; function updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName): TypeQueryNode; - function createTypeLiteralNode(members: ReadonlyArray | undefined): TypeLiteralNode; + function createTypeLiteralNode(members: ReadonlyArray | undefined, isExact?: boolean): TypeLiteralNode; function updateTypeLiteralNode(node: TypeLiteralNode, members: NodeArray): TypeLiteralNode; function createArrayTypeNode(elementType: TypeNode): ArrayTypeNode; function updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode; @@ -3758,8 +3761,8 @@ declare namespace ts { function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; - function createMappedTypeNode(readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode; - function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode; + function createMappedTypeNode(readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, isExact: boolean): MappedTypeNode; + function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, isExact: boolean): MappedTypeNode; function createLiteralTypeNode(literal: LiteralTypeNode["literal"]): LiteralTypeNode; function updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]): LiteralTypeNode; function createObjectBindingPattern(elements: ReadonlyArray): ObjectBindingPattern; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 0e693f698f253..fd8d924743e5f 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -770,6 +770,7 @@ declare namespace ts { } interface TypeLiteralNode extends TypeNode, Declaration { kind: SyntaxKind.TypeLiteral; + isExact: boolean; members: NodeArray; } interface ArrayTypeNode extends TypeNode { @@ -827,6 +828,7 @@ declare namespace ts { readonlyToken?: ReadonlyToken | PlusToken | MinusToken; typeParameter: TypeParameterDeclaration; questionToken?: QuestionToken | PlusToken | MinusToken; + isExact: boolean; type?: TypeNode; } interface LiteralTypeNode extends TypeNode { @@ -2243,6 +2245,7 @@ declare namespace ts { MarkerType = 8192, JSLiteral = 16384, FreshLiteral = 32768, + Exact = 65536, ClassOrInterface = 3 } interface ObjectType extends Type { @@ -3729,7 +3732,7 @@ declare namespace ts { function updateConstructorTypeNode(node: ConstructorTypeNode, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined): ConstructorTypeNode; function createTypeQueryNode(exprName: EntityName): TypeQueryNode; function updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName): TypeQueryNode; - function createTypeLiteralNode(members: ReadonlyArray | undefined): TypeLiteralNode; + function createTypeLiteralNode(members: ReadonlyArray | undefined, isExact?: boolean): TypeLiteralNode; function updateTypeLiteralNode(node: TypeLiteralNode, members: NodeArray): TypeLiteralNode; function createArrayTypeNode(elementType: TypeNode): ArrayTypeNode; function updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode; @@ -3758,8 +3761,8 @@ declare namespace ts { function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; - function createMappedTypeNode(readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode; - function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode; + function createMappedTypeNode(readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, isExact: boolean): MappedTypeNode; + function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, isExact: boolean): MappedTypeNode; function createLiteralTypeNode(literal: LiteralTypeNode["literal"]): LiteralTypeNode; function updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]): LiteralTypeNode; function createObjectBindingPattern(elements: ReadonlyArray): ObjectBindingPattern;