mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
const modifier on type parameters (#51865)
* `const` modifier on type parameters + revised contextual type logic * Accept new baselines * Fix modifier checking * Add tests * Cache isConstTypeVariable check * Revert "Cache isConstTypeVariable check" This reverts commit f8fd1fd29f7975fcc3aeac8675c2cb107da33065. * Fewer isConstTypeParameterContext checks * Pay attention to cached `undefined` contextual type * Allow `const` modifier in more places + properly print back * Also permit `const` in method signature type parameters * Fix parsing of `const` modifier in array expression type parameters * Accept new baselines * Remove unused properties from NodeLinks * Rename `permitInvalidConstAsModifier` to `permitConstAsModifier`
This commit is contained in:
parent
2484390af8
commit
fede84e85b
@ -195,7 +195,6 @@ import {
|
||||
FlowSwitchClause,
|
||||
FlowType,
|
||||
forEach,
|
||||
forEachAncestor,
|
||||
forEachChild,
|
||||
forEachChildRecursively,
|
||||
forEachEnclosingBlockScopeContainer,
|
||||
@ -458,6 +457,7 @@ import {
|
||||
isComputedPropertyName,
|
||||
isConstructorDeclaration,
|
||||
isConstructorTypeNode,
|
||||
isConstructSignatureDeclaration,
|
||||
isConstTypeReference,
|
||||
isDeclaration,
|
||||
isDeclarationFileName,
|
||||
@ -2065,6 +2065,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
let lastFlowNodeReachable: boolean;
|
||||
let flowTypeCache: Type[] | undefined;
|
||||
|
||||
const contextualTypeNodes: Node[] = [];
|
||||
const contextualTypes: (Type | undefined)[] = [];
|
||||
let contextualTypeCount = 0;
|
||||
|
||||
let currentInferenceNode: Node | undefined;
|
||||
let currentInferenceContext: InferenceContext | undefined;
|
||||
|
||||
const emptyStringType = getStringLiteralType("");
|
||||
const zeroType = getNumberLiteralType(0);
|
||||
const zeroBigIntType = getBigIntLiteralType({ negative: false, base10Value: "0" });
|
||||
@ -2583,10 +2590,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return nodeLinks[nodeId] || (nodeLinks[nodeId] = new (NodeLinks as any)());
|
||||
}
|
||||
|
||||
function tryGetNodeLinks(node: Node): NodeLinks | undefined {
|
||||
return node.id ? nodeLinks[node.id] : undefined;
|
||||
}
|
||||
|
||||
function isGlobalSourceFile(node: Node) {
|
||||
return node.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(node as SourceFile);
|
||||
}
|
||||
@ -7196,7 +7199,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
function typeParameterToDeclarationWithConstraint(type: TypeParameter, context: NodeBuilderContext, constraintNode: TypeNode | undefined): TypeParameterDeclaration {
|
||||
const savedContextFlags = context.flags;
|
||||
context.flags &= ~NodeBuilderFlags.WriteTypeParametersInQualifiedName; // Avoids potential infinite loop when building for a claimspace with a generic
|
||||
const modifiers = factory.createModifiersFromModifierFlags(getVarianceModifiers(type));
|
||||
const modifiers = factory.createModifiersFromModifierFlags(getTypeParameterModifiers(type));
|
||||
const name = typeParameterToName(type, context);
|
||||
const defaultParameter = getDefaultFromTypeParameter(type);
|
||||
const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, context);
|
||||
@ -13208,6 +13211,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined;
|
||||
}
|
||||
|
||||
function isConstTypeVariable(type: Type): boolean {
|
||||
return !!(type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) ||
|
||||
type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType));
|
||||
}
|
||||
|
||||
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
|
||||
return hasNonCircularBaseConstraint(type) ? getConstraintFromIndexedAccess(type) : undefined;
|
||||
}
|
||||
@ -18990,14 +18998,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function checkExpressionForMutableLocationWithContextualType(next: Expression, sourcePropType: Type) {
|
||||
const links = getNodeLinks(next);
|
||||
links.contextualType = sourcePropType;
|
||||
try {
|
||||
return checkExpressionForMutableLocation(next, CheckMode.Contextual, sourcePropType);
|
||||
}
|
||||
finally {
|
||||
links.contextualType = undefined;
|
||||
}
|
||||
pushContextualType(next, sourcePropType);
|
||||
const result = checkExpressionForMutableLocation(next, CheckMode.Contextual);
|
||||
popContextualType();
|
||||
return result;
|
||||
}
|
||||
|
||||
type ElaborationIterator = IterableIterator<{ errorNode: Node, innerExpression: Expression | undefined, nameType: Type, errorMessage?: DiagnosticMessage | undefined }>;
|
||||
@ -19239,20 +19243,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
// recreate a tuple from the elements, if possible
|
||||
// Since we're re-doing the expression type, we need to reapply the contextual type
|
||||
const links = getNodeLinks(node);
|
||||
const oldContext = links.contextualType;
|
||||
links.contextualType = target;
|
||||
try {
|
||||
const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true);
|
||||
links.contextualType = oldContext;
|
||||
if (isTupleLikeType(tupleizedType)) {
|
||||
return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation, containingMessageChain, errorOutputContainer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
links.contextualType = oldContext;
|
||||
pushContextualType(node, target);
|
||||
const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true);
|
||||
popContextualType();
|
||||
if (isTupleLikeType(tupleizedType)) {
|
||||
return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation, containingMessageChain, errorOutputContainer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function *generateObjectLiteralElements(node: ObjectLiteralExpression): ElaborationIterator {
|
||||
@ -22138,7 +22135,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
links.variances = emptyArray;
|
||||
const variances = [];
|
||||
for (const tp of typeParameters) {
|
||||
const modifiers = getVarianceModifiers(tp);
|
||||
const modifiers = getTypeParameterModifiers(tp);
|
||||
let variance = modifiers & ModifierFlags.Out ?
|
||||
modifiers & ModifierFlags.In ? VarianceFlags.Invariant : VarianceFlags.Covariant :
|
||||
modifiers & ModifierFlags.In ? VarianceFlags.Contravariant : undefined;
|
||||
@ -22196,9 +22193,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return markerTypes.has(getTypeId(type));
|
||||
}
|
||||
|
||||
function getVarianceModifiers(tp: TypeParameter): ModifierFlags {
|
||||
return (some(tp.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.In)) ? ModifierFlags.In : 0) |
|
||||
(some(tp.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Out)) ? ModifierFlags.Out: 0);
|
||||
function getTypeParameterModifiers(tp: TypeParameter): ModifierFlags {
|
||||
return reduceLeft(tp.symbol?.declarations, (modifiers, d) => modifiers | getEffectiveModifierFlags(d), ModifierFlags.None) & (ModifierFlags.In | ModifierFlags.Out | ModifierFlags.Const);
|
||||
}
|
||||
|
||||
// Return true if the given type reference has a 'void' type argument for a covariant type parameter.
|
||||
@ -24460,7 +24456,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// all inferences were made to top-level occurrences of the type parameter, and
|
||||
// the type parameter has no constraint or its constraint includes no primitive or literal types, and
|
||||
// the type parameter was fixed during inference or does not occur at top-level in the return type.
|
||||
const primitiveConstraint = hasPrimitiveConstraint(inference.typeParameter);
|
||||
const primitiveConstraint = hasPrimitiveConstraint(inference.typeParameter) || isConstTypeVariable(inference.typeParameter);
|
||||
const widenLiteralTypes = !primitiveConstraint && inference.topLevel &&
|
||||
(inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter));
|
||||
const baseCandidates = primitiveConstraint ? sameMap(candidates, getRegularTypeOfLiteralType) :
|
||||
@ -28682,9 +28678,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// We cannot answer semantic questions within a with block, do not proceed any further
|
||||
return undefined;
|
||||
}
|
||||
const contextualType = tryGetNodeLinks(node)?.contextualType;
|
||||
if (contextualType) {
|
||||
return contextualType;
|
||||
const index = findContextualNode(node);
|
||||
if (index >= 0) {
|
||||
return contextualTypes[index];
|
||||
}
|
||||
const { parent } = node;
|
||||
switch (parent.kind) {
|
||||
@ -28706,7 +28702,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return getContextualTypeForArgument(parent as CallExpression | NewExpression, node);
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
case SyntaxKind.AsExpression:
|
||||
return isConstTypeReference((parent as AssertionExpression).type) ? tryFindWhenConstTypeReference(parent as AssertionExpression) : getTypeFromTypeNode((parent as AssertionExpression).type);
|
||||
return isConstTypeReference((parent as AssertionExpression).type) ? getContextualType(parent as AssertionExpression, contextFlags) : getTypeFromTypeNode((parent as AssertionExpression).type);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return getContextualTypeForBinaryOperand(node, contextFlags);
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
@ -28728,7 +28724,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
|
||||
const tag = isInJSFile(parent) ? getJSDocTypeTag(parent) : undefined;
|
||||
return !tag ? getContextualType(parent as ParenthesizedExpression, contextFlags) :
|
||||
isJSDocTypeTag(tag) && isConstTypeReference(tag.typeExpression.type) ? tryFindWhenConstTypeReference(parent as ParenthesizedExpression) :
|
||||
isJSDocTypeTag(tag) && isConstTypeReference(tag.typeExpression.type) ? getContextualType(parent as ParenthesizedExpression, contextFlags) :
|
||||
getTypeFromTypeNode(tag.typeExpression.type);
|
||||
}
|
||||
case SyntaxKind.NonNullExpression:
|
||||
@ -28747,24 +28743,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return getContextualJsxElementAttributesType(parent as JsxOpeningLikeElement, contextFlags);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryFindWhenConstTypeReference(node: Expression) {
|
||||
return getContextualType(node, contextFlags);
|
||||
function pushContextualType(node: Node, type: Type | undefined) {
|
||||
contextualTypeNodes[contextualTypeCount] = node;
|
||||
contextualTypes[contextualTypeCount] = type;
|
||||
contextualTypeCount++;
|
||||
}
|
||||
|
||||
function popContextualType() {
|
||||
contextualTypeCount--;
|
||||
}
|
||||
|
||||
function findContextualNode(node: Node) {
|
||||
for (let i = contextualTypeCount - 1; i >= 0; i--) {
|
||||
if (node === contextualTypeNodes[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function getInferenceContext(node: Node) {
|
||||
return forEachAncestor(node, n => tryGetNodeLinks(n)?.inferenceContext);
|
||||
return isNodeDescendantOf(node, currentInferenceNode) ? currentInferenceContext : undefined;
|
||||
}
|
||||
|
||||
function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) {
|
||||
if (isJsxOpeningElement(node) && contextFlags !== ContextFlags.Completions) {
|
||||
const contextualType = tryGetNodeLinks(node.parent)?.contextualType;
|
||||
if (contextualType) {
|
||||
const index = findContextualNode(node.parent);
|
||||
if (index >= 0) {
|
||||
// Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit
|
||||
// _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type
|
||||
// (as below) instead!
|
||||
return contextualType;
|
||||
return contextualTypes[index];
|
||||
}
|
||||
}
|
||||
return getContextualTypeForArgumentAtIndex(node, 0);
|
||||
@ -29095,9 +29106,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const elementCount = elements.length;
|
||||
const elementTypes: Type[] = [];
|
||||
const elementFlags: ElementFlags[] = [];
|
||||
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
|
||||
pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined));
|
||||
const inDestructuringPattern = isAssignmentTarget(node);
|
||||
const inConstContext = isConstContext(node);
|
||||
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
|
||||
const inTupleContext = !!contextualType && someType(contextualType, isTupleLikeType);
|
||||
let hasOmittedExpression = false;
|
||||
for (let i = 0; i < elementCount; i++) {
|
||||
const e = elements[i];
|
||||
@ -29140,21 +29153,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
elementFlags.push(ElementFlags.Optional);
|
||||
}
|
||||
else {
|
||||
const elementContextualType = getContextualTypeForElementExpression(contextualType, elementTypes.length);
|
||||
const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType, forceTuple);
|
||||
const type = checkExpressionForMutableLocation(e, checkMode, forceTuple);
|
||||
elementTypes.push(addOptionality(type, /*isProperty*/ true, hasOmittedExpression));
|
||||
elementFlags.push(hasOmittedExpression ? ElementFlags.Optional : ElementFlags.Required);
|
||||
if (contextualType && someType(contextualType, isTupleLikeType) && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) {
|
||||
if (inTupleContext && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) {
|
||||
const inferenceContext = getInferenceContext(node);
|
||||
Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context
|
||||
addIntraExpressionInferenceSite(inferenceContext, e, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
popContextualType();
|
||||
if (inDestructuringPattern) {
|
||||
return createTupleType(elementTypes, elementFlags);
|
||||
}
|
||||
if (forceTuple || inConstContext || contextualType && someType(contextualType, isTupleLikeType)) {
|
||||
if (forceTuple || inConstContext || inTupleContext) {
|
||||
return createArrayLiteralType(createTupleType(elementTypes, elementFlags, /*readonly*/ inConstContext));
|
||||
}
|
||||
return createArrayLiteralType(createArrayType(elementTypes.length ?
|
||||
@ -29276,6 +29289,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
let propertiesArray: Symbol[] = [];
|
||||
let spread: Type = emptyObjectType;
|
||||
|
||||
pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined));
|
||||
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
|
||||
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
|
||||
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
|
||||
@ -29436,6 +29450,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
propertiesArray.push(member);
|
||||
}
|
||||
popContextualType();
|
||||
|
||||
// If object literal is contextually typed by the implied type of a binding pattern, augment the result
|
||||
// type with those properties for which the binding pattern specifies a default value.
|
||||
@ -31644,6 +31659,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const types = [];
|
||||
const flags = [];
|
||||
const names = [];
|
||||
const inConstContext = isConstTypeVariable(restType);
|
||||
for (let i = index; i < argCount; i++) {
|
||||
const arg = args[i];
|
||||
if (isSpreadArgument(arg)) {
|
||||
@ -31660,7 +31676,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
else {
|
||||
const contextualType = getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual);
|
||||
const argType = checkExpressionWithContextualType(arg, contextualType, context, checkMode);
|
||||
const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping);
|
||||
const hasPrimitiveContextualType = inConstContext || maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping);
|
||||
types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType));
|
||||
flags.push(ElementFlags.Required);
|
||||
}
|
||||
@ -31668,7 +31684,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
names.push((arg as SyntheticExpression).tupleNameSource!);
|
||||
}
|
||||
}
|
||||
return createTupleType(types, flags, /*readonly*/ false, length(names) === length(types) ? names : undefined);
|
||||
return createTupleType(types, flags, inConstContext, length(names) === length(types) ? names : undefined);
|
||||
}
|
||||
|
||||
function checkTypeArguments(signature: Signature, typeArgumentNodes: readonly TypeNode[], reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | undefined {
|
||||
@ -33124,7 +33140,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (isJsxIntrinsicIdentifier(node.tagName)) {
|
||||
const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node);
|
||||
const fakeSignature = createSignatureForJSXIntrinsic(node, result);
|
||||
checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes);
|
||||
checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*inferenceContext*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes);
|
||||
if (length(node.typeArguments)) {
|
||||
forEach(node.typeArguments, checkSourceElement);
|
||||
diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), node.typeArguments!, Diagnostics.Expected_0_type_arguments_but_got_1, 0, length(node.typeArguments)));
|
||||
@ -33602,12 +33618,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral;
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
const expr = (node as PropertyAccessExpression | ElementAccessExpression).expression;
|
||||
let symbol = getTypeOfNode(expr).symbol;
|
||||
if (symbol && symbol.flags & SymbolFlags.Alias) {
|
||||
symbol = resolveAlias(symbol);
|
||||
}
|
||||
return !!(symbol && getAllSymbolFlags(symbol) & SymbolFlags.Enum);
|
||||
const expr = skipParentheses((node as PropertyAccessExpression | ElementAccessExpression).expression);
|
||||
const symbol = isEntityNameExpression(expr) ? resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true) : undefined;
|
||||
return !!(symbol && symbol.flags & SymbolFlags.Enum);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -36007,33 +36020,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type {
|
||||
const context = getContextNode(node);
|
||||
const links = getNodeLinks(context);
|
||||
const saveContextualType = links.contextualType;
|
||||
const saveInferenceContext = links.inferenceContext;
|
||||
try {
|
||||
links.contextualType = contextualType;
|
||||
links.inferenceContext = inferenceContext;
|
||||
const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0));
|
||||
// In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type
|
||||
// parameters. This information is no longer needed after the call to checkExpression.
|
||||
if (inferenceContext && inferenceContext.intraExpressionInferenceSites) {
|
||||
inferenceContext.intraExpressionInferenceSites = undefined;
|
||||
}
|
||||
// We strip literal freshness when an appropriate contextual type is present such that contextually typed
|
||||
// literals always preserve their literal types (otherwise they might widen during type inference). An alternative
|
||||
// here would be to not mark contextually typed literals as fresh in the first place.
|
||||
const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node, /*contextFlags*/ undefined)) ?
|
||||
getRegularTypeOfLiteralType(type) : type;
|
||||
return result;
|
||||
}
|
||||
finally {
|
||||
// In the event our operation is canceled or some other exception occurs, reset the contextual type
|
||||
// so that we do not accidentally hold onto an instance of the checker, as a Type created in the services layer
|
||||
// may hold onto the checker that created it.
|
||||
links.contextualType = saveContextualType;
|
||||
links.inferenceContext = saveInferenceContext;
|
||||
const contextNode = getContextNode(node);
|
||||
pushContextualType(contextNode, contextualType);
|
||||
const saveInferenceNode = currentInferenceNode;
|
||||
const saveInferenceContext = currentInferenceContext;
|
||||
currentInferenceNode = contextNode;
|
||||
currentInferenceContext = inferenceContext;
|
||||
const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0));
|
||||
// In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type
|
||||
// parameters. This information is no longer needed after the call to checkExpression.
|
||||
if (inferenceContext && inferenceContext.intraExpressionInferenceSites) {
|
||||
inferenceContext.intraExpressionInferenceSites = undefined;
|
||||
}
|
||||
// We strip literal freshness when an appropriate contextual type is present such that contextually typed
|
||||
// literals always preserve their literal types (otherwise they might widen during type inference). An alternative
|
||||
// here would be to not mark contextually typed literals as fresh in the first place.
|
||||
const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node, /*contextFlags*/ undefined)) ?
|
||||
getRegularTypeOfLiteralType(type) : type;
|
||||
currentInferenceNode = saveInferenceNode;
|
||||
currentInferenceContext = saveInferenceContext;
|
||||
popContextualType();
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkExpressionCached(node: Expression | QualifiedName, checkMode?: CheckMode): Type {
|
||||
@ -36142,15 +36149,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const parent = node.parent;
|
||||
return isAssertionExpression(parent) && isConstTypeReference(parent.type) ||
|
||||
isJSDocTypeAssertion(parent) && isConstTypeReference(getJSDocTypeAssertionType(parent)) ||
|
||||
isValidConstAssertionArgument(node) && isConstTypeParameterContext(node) ||
|
||||
(isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) && isConstContext(parent) ||
|
||||
(isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent) || isTemplateSpan(parent)) && isConstContext(parent.parent);
|
||||
}
|
||||
|
||||
function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type {
|
||||
function isConstTypeParameterContext(node: Expression) {
|
||||
const contextualType = getContextualType(node, ContextFlags.None);
|
||||
return !!contextualType && someType(contextualType, isConstTypeVariable);
|
||||
}
|
||||
|
||||
function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, forceTuple?: boolean): Type {
|
||||
const type = checkExpression(node, checkMode, forceTuple);
|
||||
return isConstContext(node) || isCommonJsExportedExpression(node) ? getRegularTypeOfLiteralType(type) :
|
||||
isTypeAssertion(node) ? type :
|
||||
getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(arguments.length === 2 ? getContextualType(node, /*contextFlags*/ undefined) : contextualType, node, /*contextFlags*/ undefined));
|
||||
getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(getContextualType(node, /*contextFlags*/ undefined), node, /*contextFlags*/ undefined));
|
||||
}
|
||||
|
||||
function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type {
|
||||
@ -36397,18 +36410,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (links.contextFreeType) {
|
||||
return links.contextFreeType;
|
||||
}
|
||||
const saveContextualType = links.contextualType;
|
||||
links.contextualType = anyType;
|
||||
try {
|
||||
const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive);
|
||||
return type;
|
||||
}
|
||||
finally {
|
||||
// In the event our operation is canceled or some other exception occurs, reset the contextual type
|
||||
// so that we do not accidentally hold onto an instance of the checker, as a Type created in the services layer
|
||||
// may hold onto the checker that created it.
|
||||
links.contextualType = saveContextualType;
|
||||
}
|
||||
pushContextualType(node, anyType);
|
||||
const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive);
|
||||
popContextualType();
|
||||
return type;
|
||||
}
|
||||
|
||||
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
|
||||
@ -36608,7 +36613,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
function checkTypeParameterDeferred(node: TypeParameterDeclaration) {
|
||||
if (isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent)) {
|
||||
const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(node));
|
||||
const modifiers = getVarianceModifiers(typeParameter);
|
||||
const modifiers = getTypeParameterModifiers(typeParameter) & (ModifierFlags.In | ModifierFlags.Out);
|
||||
if (modifiers) {
|
||||
const symbol = getSymbolOfDeclaration(node.parent);
|
||||
if (isTypeAliasDeclaration(node.parent) && !(getObjectFlags(getDeclaredTypeOfSymbol(symbol)) & (ObjectFlags.Anonymous | ObjectFlags.Mapped))) {
|
||||
@ -45444,16 +45449,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_index_signature, tokenToString(modifier.kind));
|
||||
}
|
||||
}
|
||||
if (modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword) {
|
||||
if (modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword && modifier.kind !== SyntaxKind.ConstKeyword) {
|
||||
if (node.kind === SyntaxKind.TypeParameter) {
|
||||
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_parameter, tokenToString(modifier.kind));
|
||||
}
|
||||
}
|
||||
switch (modifier.kind) {
|
||||
case SyntaxKind.ConstKeyword:
|
||||
if (node.kind !== SyntaxKind.EnumDeclaration) {
|
||||
if (node.kind !== SyntaxKind.EnumDeclaration && node.kind !== SyntaxKind.TypeParameter) {
|
||||
return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword));
|
||||
}
|
||||
const parent = node.parent;
|
||||
if (node.kind === SyntaxKind.TypeParameter && !(isFunctionLikeDeclaration(parent) || isClassDeclaration(parent) || isFunctionTypeNode(parent) ||
|
||||
isConstructorTypeNode(parent) || isCallSignatureDeclaration(parent) || isConstructSignatureDeclaration(parent) || isMethodSignature(parent))) {
|
||||
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_method_or_class, tokenToString(modifier.kind));
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.OverrideKeyword:
|
||||
// If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property.
|
||||
|
||||
@ -907,6 +907,10 @@
|
||||
"category": "Error",
|
||||
"code": 1276
|
||||
},
|
||||
"'{0}' modifier can only appear on a type parameter of a function, method or class": {
|
||||
"category": "Error",
|
||||
"code": 1277
|
||||
},
|
||||
|
||||
"'with' statements are not allowed in an async function block.": {
|
||||
"category": "Error",
|
||||
|
||||
@ -2816,7 +2816,7 @@ namespace Parser {
|
||||
case ParsingContext.ArrayBindingElements:
|
||||
return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern();
|
||||
case ParsingContext.TypeParameters:
|
||||
return token() === SyntaxKind.InKeyword || isIdentifier();
|
||||
return token() === SyntaxKind.InKeyword || token() === SyntaxKind.ConstKeyword || isIdentifier();
|
||||
case ParsingContext.ArrayLiteralMembers:
|
||||
switch (token()) {
|
||||
case SyntaxKind.CommaToken:
|
||||
@ -3825,7 +3825,7 @@ namespace Parser {
|
||||
|
||||
function parseTypeParameter(): TypeParameterDeclaration {
|
||||
const pos = getNodePos();
|
||||
const modifiers = parseModifiers();
|
||||
const modifiers = parseModifiers(/*permitConstAsModifier*/ true);
|
||||
const name = parseIdentifier();
|
||||
let constraint: TypeNode | undefined;
|
||||
let expression: Expression | undefined;
|
||||
@ -5205,13 +5205,14 @@ namespace Parser {
|
||||
|
||||
// If we have "<" not followed by an identifier,
|
||||
// then this definitely is not an arrow function.
|
||||
if (!isIdentifier()) {
|
||||
if (!isIdentifier() && token() !== SyntaxKind.ConstKeyword) {
|
||||
return Tristate.False;
|
||||
}
|
||||
|
||||
// JSX overrides
|
||||
if (languageVariant === LanguageVariant.JSX) {
|
||||
const isArrowFunctionInJsx = lookAhead(() => {
|
||||
parseOptional(SyntaxKind.ConstKeyword);
|
||||
const third = nextToken();
|
||||
if (third === SyntaxKind.ExtendsKeyword) {
|
||||
const fourth = nextToken();
|
||||
@ -7703,11 +7704,11 @@ namespace Parser {
|
||||
return list && createNodeArray(list, pos);
|
||||
}
|
||||
|
||||
function tryParseModifier(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean, hasSeenStaticModifier?: boolean): Modifier | undefined {
|
||||
function tryParseModifier(permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean, hasSeenStaticModifier?: boolean): Modifier | undefined {
|
||||
const pos = getNodePos();
|
||||
const kind = token();
|
||||
|
||||
if (token() === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) {
|
||||
if (token() === SyntaxKind.ConstKeyword && permitConstAsModifier) {
|
||||
// We need to ensure that any subsequent modifiers appear on the same line
|
||||
// so that when 'const' is a standalone declaration, we don't issue an error.
|
||||
if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) {
|
||||
@ -7742,12 +7743,12 @@ namespace Parser {
|
||||
* In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect
|
||||
* and turns it into a standalone declaration), then it is better to parse it and report an error later.
|
||||
*
|
||||
* In such situations, 'permitInvalidConstAsModifier' should be set to true.
|
||||
* In such situations, 'permitConstAsModifier' should be set to true.
|
||||
*/
|
||||
function parseModifiers(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray<Modifier> | undefined {
|
||||
function parseModifiers(permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray<Modifier> | undefined {
|
||||
const pos = getNodePos();
|
||||
let list, modifier, hasSeenStatic = false;
|
||||
while (modifier = tryParseModifier(permitInvalidConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic)) {
|
||||
while (modifier = tryParseModifier(permitConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic)) {
|
||||
if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStatic = true;
|
||||
list = append(list, modifier);
|
||||
}
|
||||
@ -7774,7 +7775,7 @@ namespace Parser {
|
||||
|
||||
const hasJSDoc = hasPrecedingJSDocComment();
|
||||
const decorators = parseDecorators();
|
||||
const modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true);
|
||||
const modifiers = parseModifiers(/*permitConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true);
|
||||
if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) {
|
||||
return parseClassStaticBlockDeclaration(pos, hasJSDoc, decorators, modifiers);
|
||||
}
|
||||
|
||||
@ -5985,9 +5985,6 @@ export interface NodeLinks {
|
||||
skipDirectInference?: true; // Flag set by the API `getContextualType` call on a node when `Completions` is passed to force the checker to skip making inferences to a node's type
|
||||
declarationRequiresScopeChange?: boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter.
|
||||
serializedTypes?: Map<string, SerializedTypeEntry>; // Collection of types serialized at this location
|
||||
|
||||
contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
|
||||
inferenceContext?: InferenceContext; // Inference context for contextual type
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
@ -623,6 +623,7 @@ Info 32 [00:01:13.000] response:
|
||||
"1274",
|
||||
"1275",
|
||||
"1276",
|
||||
"1277",
|
||||
"1300",
|
||||
"1309",
|
||||
"1313",
|
||||
@ -1952,6 +1953,7 @@ Info 38 [00:01:19.000] response:
|
||||
"1274",
|
||||
"1275",
|
||||
"1276",
|
||||
"1277",
|
||||
"1300",
|
||||
"1309",
|
||||
"1313",
|
||||
@ -3193,6 +3195,7 @@ Info 40 [00:01:21.000] response:
|
||||
"1274",
|
||||
"1275",
|
||||
"1276",
|
||||
"1277",
|
||||
"1300",
|
||||
"1309",
|
||||
"1313",
|
||||
|
||||
@ -0,0 +1,80 @@
|
||||
tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(43,14): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class
|
||||
tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(49,9): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts (2 errors) ====
|
||||
declare function f1<const T>(x: T): T;
|
||||
|
||||
const x11 = f1('a');
|
||||
const x12 = f1(['a', ['b', 'c']]);
|
||||
const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
|
||||
declare function f2<const T, U>(x: T | undefined): T;
|
||||
|
||||
const x21 = f2('a');
|
||||
const x22 = f2(['a', ['b', 'c']]);
|
||||
const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
|
||||
declare function f3<const T>(x: T): T[];
|
||||
|
||||
const x31 = f3("hello");
|
||||
const x32 = f3("hello");
|
||||
|
||||
declare function f4<const T>(obj: [T, T]): T;
|
||||
|
||||
const x41 = f4([[1, 'x'], [2, 'y']]);
|
||||
const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]);
|
||||
|
||||
declare function f5<const T>(obj: { x: T, y: T }): T;
|
||||
|
||||
const x51 = f5({ x: [1, 'x'], y: [2, 'y'] });
|
||||
const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } });
|
||||
|
||||
declare function f6<const T extends readonly unknown[]>(...args: T): T;
|
||||
|
||||
const x61 = f6(1, 'b', { a: 1, b: 'x' });
|
||||
|
||||
class C1<const T> {
|
||||
constructor(x: T) {}
|
||||
foo<const U>(x: U) { return x; }
|
||||
}
|
||||
|
||||
const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
const c72 = c71.foo(['a', ['b', 'c']]);
|
||||
|
||||
const fx1 = <const T>(x: T) => x;
|
||||
const fx2 = <const T,>(x: T) => x;
|
||||
|
||||
interface I1<const T> { x: T } // Error
|
||||
~~~~~
|
||||
!!! error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class
|
||||
|
||||
interface I2 {
|
||||
f<const T>(x: T): T;
|
||||
}
|
||||
|
||||
type T1<const T> = T; // Error
|
||||
~~~~~
|
||||
!!! error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class
|
||||
|
||||
type T2 = <const T>(x: T) => T;
|
||||
type T3 = { <const T>(x: T): T };
|
||||
type T4 = new <const T>(x: T) => T;
|
||||
type T5 = { new <const T>(x: T): T };
|
||||
|
||||
// Corrected repro from #51745
|
||||
|
||||
type Obj = { a: { b: { c: "123" } } };
|
||||
|
||||
type GetPath<T, P> =
|
||||
P extends readonly [] ? T :
|
||||
P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath<T[A], Rest> :
|
||||
never;
|
||||
|
||||
function set<T, const P extends readonly string[]>(obj: T, path: P, value: GetPath<T, P>) {}
|
||||
|
||||
declare let obj: Obj;
|
||||
declare let value: "123";
|
||||
|
||||
set(obj, ['a', 'b', 'c'], value);
|
||||
|
||||
100
tests/baselines/reference/typeParameterConstModifiers.js
Normal file
100
tests/baselines/reference/typeParameterConstModifiers.js
Normal file
@ -0,0 +1,100 @@
|
||||
//// [typeParameterConstModifiers.ts]
|
||||
declare function f1<const T>(x: T): T;
|
||||
|
||||
const x11 = f1('a');
|
||||
const x12 = f1(['a', ['b', 'c']]);
|
||||
const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
|
||||
declare function f2<const T, U>(x: T | undefined): T;
|
||||
|
||||
const x21 = f2('a');
|
||||
const x22 = f2(['a', ['b', 'c']]);
|
||||
const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
|
||||
declare function f3<const T>(x: T): T[];
|
||||
|
||||
const x31 = f3("hello");
|
||||
const x32 = f3("hello");
|
||||
|
||||
declare function f4<const T>(obj: [T, T]): T;
|
||||
|
||||
const x41 = f4([[1, 'x'], [2, 'y']]);
|
||||
const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]);
|
||||
|
||||
declare function f5<const T>(obj: { x: T, y: T }): T;
|
||||
|
||||
const x51 = f5({ x: [1, 'x'], y: [2, 'y'] });
|
||||
const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } });
|
||||
|
||||
declare function f6<const T extends readonly unknown[]>(...args: T): T;
|
||||
|
||||
const x61 = f6(1, 'b', { a: 1, b: 'x' });
|
||||
|
||||
class C1<const T> {
|
||||
constructor(x: T) {}
|
||||
foo<const U>(x: U) { return x; }
|
||||
}
|
||||
|
||||
const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
const c72 = c71.foo(['a', ['b', 'c']]);
|
||||
|
||||
const fx1 = <const T>(x: T) => x;
|
||||
const fx2 = <const T,>(x: T) => x;
|
||||
|
||||
interface I1<const T> { x: T } // Error
|
||||
|
||||
interface I2 {
|
||||
f<const T>(x: T): T;
|
||||
}
|
||||
|
||||
type T1<const T> = T; // Error
|
||||
|
||||
type T2 = <const T>(x: T) => T;
|
||||
type T3 = { <const T>(x: T): T };
|
||||
type T4 = new <const T>(x: T) => T;
|
||||
type T5 = { new <const T>(x: T): T };
|
||||
|
||||
// Corrected repro from #51745
|
||||
|
||||
type Obj = { a: { b: { c: "123" } } };
|
||||
|
||||
type GetPath<T, P> =
|
||||
P extends readonly [] ? T :
|
||||
P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath<T[A], Rest> :
|
||||
never;
|
||||
|
||||
function set<T, const P extends readonly string[]>(obj: T, path: P, value: GetPath<T, P>) {}
|
||||
|
||||
declare let obj: Obj;
|
||||
declare let value: "123";
|
||||
|
||||
set(obj, ['a', 'b', 'c'], value);
|
||||
|
||||
|
||||
//// [typeParameterConstModifiers.js]
|
||||
"use strict";
|
||||
var x11 = f1('a');
|
||||
var x12 = f1(['a', ['b', 'c']]);
|
||||
var x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
var x21 = f2('a');
|
||||
var x22 = f2(['a', ['b', 'c']]);
|
||||
var x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
var x31 = f3("hello");
|
||||
var x32 = f3("hello");
|
||||
var x41 = f4([[1, 'x'], [2, 'y']]);
|
||||
var x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]);
|
||||
var x51 = f5({ x: [1, 'x'], y: [2, 'y'] });
|
||||
var x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } });
|
||||
var x61 = f6(1, 'b', { a: 1, b: 'x' });
|
||||
var C1 = /** @class */ (function () {
|
||||
function C1(x) {
|
||||
}
|
||||
C1.prototype.foo = function (x) { return x; };
|
||||
return C1;
|
||||
}());
|
||||
var c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
var c72 = c71.foo(['a', ['b', 'c']]);
|
||||
var fx1 = function (x) { return x; };
|
||||
var fx2 = function (x) { return x; };
|
||||
function set(obj, path, value) { }
|
||||
set(obj, ['a', 'b', 'c'], value);
|
||||
270
tests/baselines/reference/typeParameterConstModifiers.symbols
Normal file
270
tests/baselines/reference/typeParameterConstModifiers.symbols
Normal file
@ -0,0 +1,270 @@
|
||||
=== tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts ===
|
||||
declare function f1<const T>(x: T): T;
|
||||
>f1 : Symbol(f1, Decl(typeParameterConstModifiers.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 0, 20))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 0, 29))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 0, 20))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 0, 20))
|
||||
|
||||
const x11 = f1('a');
|
||||
>x11 : Symbol(x11, Decl(typeParameterConstModifiers.ts, 2, 5))
|
||||
>f1 : Symbol(f1, Decl(typeParameterConstModifiers.ts, 0, 0))
|
||||
|
||||
const x12 = f1(['a', ['b', 'c']]);
|
||||
>x12 : Symbol(x12, Decl(typeParameterConstModifiers.ts, 3, 5))
|
||||
>f1 : Symbol(f1, Decl(typeParameterConstModifiers.ts, 0, 0))
|
||||
|
||||
const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
>x13 : Symbol(x13, Decl(typeParameterConstModifiers.ts, 4, 5))
|
||||
>f1 : Symbol(f1, Decl(typeParameterConstModifiers.ts, 0, 0))
|
||||
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 4, 16))
|
||||
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 4, 22))
|
||||
>d : Symbol(d, Decl(typeParameterConstModifiers.ts, 4, 30))
|
||||
>f : Symbol(f, Decl(typeParameterConstModifiers.ts, 4, 50))
|
||||
|
||||
declare function f2<const T, U>(x: T | undefined): T;
|
||||
>f2 : Symbol(f2, Decl(typeParameterConstModifiers.ts, 4, 64))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 6, 20))
|
||||
>U : Symbol(U, Decl(typeParameterConstModifiers.ts, 6, 28))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 6, 32))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 6, 20))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 6, 20))
|
||||
|
||||
const x21 = f2('a');
|
||||
>x21 : Symbol(x21, Decl(typeParameterConstModifiers.ts, 8, 5))
|
||||
>f2 : Symbol(f2, Decl(typeParameterConstModifiers.ts, 4, 64))
|
||||
|
||||
const x22 = f2(['a', ['b', 'c']]);
|
||||
>x22 : Symbol(x22, Decl(typeParameterConstModifiers.ts, 9, 5))
|
||||
>f2 : Symbol(f2, Decl(typeParameterConstModifiers.ts, 4, 64))
|
||||
|
||||
const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
>x23 : Symbol(x23, Decl(typeParameterConstModifiers.ts, 10, 5))
|
||||
>f2 : Symbol(f2, Decl(typeParameterConstModifiers.ts, 4, 64))
|
||||
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 10, 16))
|
||||
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 10, 22))
|
||||
>d : Symbol(d, Decl(typeParameterConstModifiers.ts, 10, 30))
|
||||
>f : Symbol(f, Decl(typeParameterConstModifiers.ts, 10, 50))
|
||||
|
||||
declare function f3<const T>(x: T): T[];
|
||||
>f3 : Symbol(f3, Decl(typeParameterConstModifiers.ts, 10, 64))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 12, 20))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 12, 29))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 12, 20))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 12, 20))
|
||||
|
||||
const x31 = f3("hello");
|
||||
>x31 : Symbol(x31, Decl(typeParameterConstModifiers.ts, 14, 5))
|
||||
>f3 : Symbol(f3, Decl(typeParameterConstModifiers.ts, 10, 64))
|
||||
|
||||
const x32 = f3("hello");
|
||||
>x32 : Symbol(x32, Decl(typeParameterConstModifiers.ts, 15, 5))
|
||||
>f3 : Symbol(f3, Decl(typeParameterConstModifiers.ts, 10, 64))
|
||||
|
||||
declare function f4<const T>(obj: [T, T]): T;
|
||||
>f4 : Symbol(f4, Decl(typeParameterConstModifiers.ts, 15, 24))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 17, 20))
|
||||
>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 17, 29))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 17, 20))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 17, 20))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 17, 20))
|
||||
|
||||
const x41 = f4([[1, 'x'], [2, 'y']]);
|
||||
>x41 : Symbol(x41, Decl(typeParameterConstModifiers.ts, 19, 5))
|
||||
>f4 : Symbol(f4, Decl(typeParameterConstModifiers.ts, 15, 24))
|
||||
|
||||
const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]);
|
||||
>x42 : Symbol(x42, Decl(typeParameterConstModifiers.ts, 20, 5))
|
||||
>f4 : Symbol(f4, Decl(typeParameterConstModifiers.ts, 15, 24))
|
||||
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 20, 17))
|
||||
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 20, 23))
|
||||
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 20, 35))
|
||||
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 20, 41))
|
||||
|
||||
declare function f5<const T>(obj: { x: T, y: T }): T;
|
||||
>f5 : Symbol(f5, Decl(typeParameterConstModifiers.ts, 20, 53))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 22, 20))
|
||||
>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 22, 29))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 22, 35))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 22, 20))
|
||||
>y : Symbol(y, Decl(typeParameterConstModifiers.ts, 22, 41))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 22, 20))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 22, 20))
|
||||
|
||||
const x51 = f5({ x: [1, 'x'], y: [2, 'y'] });
|
||||
>x51 : Symbol(x51, Decl(typeParameterConstModifiers.ts, 24, 5))
|
||||
>f5 : Symbol(f5, Decl(typeParameterConstModifiers.ts, 20, 53))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 24, 16))
|
||||
>y : Symbol(y, Decl(typeParameterConstModifiers.ts, 24, 29))
|
||||
|
||||
const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } });
|
||||
>x52 : Symbol(x52, Decl(typeParameterConstModifiers.ts, 25, 5))
|
||||
>f5 : Symbol(f5, Decl(typeParameterConstModifiers.ts, 20, 53))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 25, 16))
|
||||
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 25, 21))
|
||||
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 25, 27))
|
||||
>y : Symbol(y, Decl(typeParameterConstModifiers.ts, 25, 37))
|
||||
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 25, 42))
|
||||
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 25, 48))
|
||||
|
||||
declare function f6<const T extends readonly unknown[]>(...args: T): T;
|
||||
>f6 : Symbol(f6, Decl(typeParameterConstModifiers.ts, 25, 61))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 27, 20))
|
||||
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 27, 56))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 27, 20))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 27, 20))
|
||||
|
||||
const x61 = f6(1, 'b', { a: 1, b: 'x' });
|
||||
>x61 : Symbol(x61, Decl(typeParameterConstModifiers.ts, 29, 5))
|
||||
>f6 : Symbol(f6, Decl(typeParameterConstModifiers.ts, 25, 61))
|
||||
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 29, 24))
|
||||
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 29, 30))
|
||||
|
||||
class C1<const T> {
|
||||
>C1 : Symbol(C1, Decl(typeParameterConstModifiers.ts, 29, 41))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 31, 9))
|
||||
|
||||
constructor(x: T) {}
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 32, 16))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 31, 9))
|
||||
|
||||
foo<const U>(x: U) { return x; }
|
||||
>foo : Symbol(C1.foo, Decl(typeParameterConstModifiers.ts, 32, 24))
|
||||
>U : Symbol(U, Decl(typeParameterConstModifiers.ts, 33, 8))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 33, 17))
|
||||
>U : Symbol(U, Decl(typeParameterConstModifiers.ts, 33, 8))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 33, 17))
|
||||
}
|
||||
|
||||
const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
>c71 : Symbol(c71, Decl(typeParameterConstModifiers.ts, 36, 5))
|
||||
>C1 : Symbol(C1, Decl(typeParameterConstModifiers.ts, 29, 41))
|
||||
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 36, 20))
|
||||
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 36, 26))
|
||||
>d : Symbol(d, Decl(typeParameterConstModifiers.ts, 36, 34))
|
||||
>f : Symbol(f, Decl(typeParameterConstModifiers.ts, 36, 54))
|
||||
|
||||
const c72 = c71.foo(['a', ['b', 'c']]);
|
||||
>c72 : Symbol(c72, Decl(typeParameterConstModifiers.ts, 37, 5))
|
||||
>c71.foo : Symbol(C1.foo, Decl(typeParameterConstModifiers.ts, 32, 24))
|
||||
>c71 : Symbol(c71, Decl(typeParameterConstModifiers.ts, 36, 5))
|
||||
>foo : Symbol(C1.foo, Decl(typeParameterConstModifiers.ts, 32, 24))
|
||||
|
||||
const fx1 = <const T>(x: T) => x;
|
||||
>fx1 : Symbol(fx1, Decl(typeParameterConstModifiers.ts, 39, 5))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 39, 13))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 39, 22))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 39, 13))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 39, 22))
|
||||
|
||||
const fx2 = <const T,>(x: T) => x;
|
||||
>fx2 : Symbol(fx2, Decl(typeParameterConstModifiers.ts, 40, 5))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 40, 13))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 40, 23))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 40, 13))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 40, 23))
|
||||
|
||||
interface I1<const T> { x: T } // Error
|
||||
>I1 : Symbol(I1, Decl(typeParameterConstModifiers.ts, 40, 34))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 42, 13))
|
||||
>x : Symbol(I1.x, Decl(typeParameterConstModifiers.ts, 42, 23))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 42, 13))
|
||||
|
||||
interface I2 {
|
||||
>I2 : Symbol(I2, Decl(typeParameterConstModifiers.ts, 42, 30))
|
||||
|
||||
f<const T>(x: T): T;
|
||||
>f : Symbol(I2.f, Decl(typeParameterConstModifiers.ts, 44, 14))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 6))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 45, 15))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 6))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 6))
|
||||
}
|
||||
|
||||
type T1<const T> = T; // Error
|
||||
>T1 : Symbol(T1, Decl(typeParameterConstModifiers.ts, 46, 1))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 48, 8))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 48, 8))
|
||||
|
||||
type T2 = <const T>(x: T) => T;
|
||||
>T2 : Symbol(T2, Decl(typeParameterConstModifiers.ts, 48, 21))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 11))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 50, 20))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 11))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 11))
|
||||
|
||||
type T3 = { <const T>(x: T): T };
|
||||
>T3 : Symbol(T3, Decl(typeParameterConstModifiers.ts, 50, 31))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 51, 13))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 51, 22))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 51, 13))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 51, 13))
|
||||
|
||||
type T4 = new <const T>(x: T) => T;
|
||||
>T4 : Symbol(T4, Decl(typeParameterConstModifiers.ts, 51, 33))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 15))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 52, 24))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 15))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 15))
|
||||
|
||||
type T5 = { new <const T>(x: T): T };
|
||||
>T5 : Symbol(T5, Decl(typeParameterConstModifiers.ts, 52, 35))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 53, 17))
|
||||
>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 53, 26))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 53, 17))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 53, 17))
|
||||
|
||||
// Corrected repro from #51745
|
||||
|
||||
type Obj = { a: { b: { c: "123" } } };
|
||||
>Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 53, 37))
|
||||
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 57, 12))
|
||||
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 57, 17))
|
||||
>c : Symbol(c, Decl(typeParameterConstModifiers.ts, 57, 22))
|
||||
|
||||
type GetPath<T, P> =
|
||||
>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 57, 38))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 59, 13))
|
||||
>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 59, 15))
|
||||
|
||||
P extends readonly [] ? T :
|
||||
>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 59, 15))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 59, 13))
|
||||
|
||||
P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath<T[A], Rest> :
|
||||
>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 59, 15))
|
||||
>A : Symbol(A, Decl(typeParameterConstModifiers.ts, 61, 29))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 59, 13))
|
||||
>Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 61, 57))
|
||||
>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 57, 38))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 59, 13))
|
||||
>A : Symbol(A, Decl(typeParameterConstModifiers.ts, 61, 29))
|
||||
>Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 61, 57))
|
||||
|
||||
never;
|
||||
|
||||
function set<T, const P extends readonly string[]>(obj: T, path: P, value: GetPath<T, P>) {}
|
||||
>set : Symbol(set, Decl(typeParameterConstModifiers.ts, 62, 10))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 64, 13))
|
||||
>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 64, 15))
|
||||
>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 64, 51))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 64, 13))
|
||||
>path : Symbol(path, Decl(typeParameterConstModifiers.ts, 64, 58))
|
||||
>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 64, 15))
|
||||
>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 64, 67))
|
||||
>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 57, 38))
|
||||
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 64, 13))
|
||||
>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 64, 15))
|
||||
|
||||
declare let obj: Obj;
|
||||
>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 66, 11))
|
||||
>Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 53, 37))
|
||||
|
||||
declare let value: "123";
|
||||
>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 67, 11))
|
||||
|
||||
set(obj, ['a', 'b', 'c'], value);
|
||||
>set : Symbol(set, Decl(typeParameterConstModifiers.ts, 62, 10))
|
||||
>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 66, 11))
|
||||
>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 67, 11))
|
||||
|
||||
298
tests/baselines/reference/typeParameterConstModifiers.types
Normal file
298
tests/baselines/reference/typeParameterConstModifiers.types
Normal file
@ -0,0 +1,298 @@
|
||||
=== tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts ===
|
||||
declare function f1<const T>(x: T): T;
|
||||
>f1 : <const T>(x: T) => T
|
||||
>x : T
|
||||
|
||||
const x11 = f1('a');
|
||||
>x11 : "a"
|
||||
>f1('a') : "a"
|
||||
>f1 : <const T>(x: T) => T
|
||||
>'a' : "a"
|
||||
|
||||
const x12 = f1(['a', ['b', 'c']]);
|
||||
>x12 : readonly ["a", readonly ["b", "c"]]
|
||||
>f1(['a', ['b', 'c']]) : readonly ["a", readonly ["b", "c"]]
|
||||
>f1 : <const T>(x: T) => T
|
||||
>['a', ['b', 'c']] : ["a", ["b", "c"]]
|
||||
>'a' : "a"
|
||||
>['b', 'c'] : ["b", "c"]
|
||||
>'b' : "b"
|
||||
>'c' : "c"
|
||||
|
||||
const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
>x13 : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }
|
||||
>f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }
|
||||
>f1 : <const T>(x: T) => T
|
||||
>{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; }
|
||||
>a : 1
|
||||
>1 : 1
|
||||
>b : "c"
|
||||
>"c" : "c"
|
||||
>d : ["e", 2, true, { f: "g"; }]
|
||||
>["e", 2, true, { f: "g" }] : ["e", 2, true, { f: "g"; }]
|
||||
>"e" : "e"
|
||||
>2 : 2
|
||||
>true : true
|
||||
>{ f: "g" } : { f: "g"; }
|
||||
>f : "g"
|
||||
>"g" : "g"
|
||||
|
||||
declare function f2<const T, U>(x: T | undefined): T;
|
||||
>f2 : <const T, U>(x: T | undefined) => T
|
||||
>x : T | undefined
|
||||
|
||||
const x21 = f2('a');
|
||||
>x21 : "a"
|
||||
>f2('a') : "a"
|
||||
>f2 : <const T, U>(x: T | undefined) => T
|
||||
>'a' : "a"
|
||||
|
||||
const x22 = f2(['a', ['b', 'c']]);
|
||||
>x22 : readonly ["a", readonly ["b", "c"]]
|
||||
>f2(['a', ['b', 'c']]) : readonly ["a", readonly ["b", "c"]]
|
||||
>f2 : <const T, U>(x: T | undefined) => T
|
||||
>['a', ['b', 'c']] : ["a", ["b", "c"]]
|
||||
>'a' : "a"
|
||||
>['b', 'c'] : ["b", "c"]
|
||||
>'b' : "b"
|
||||
>'c' : "c"
|
||||
|
||||
const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
>x23 : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }
|
||||
>f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }
|
||||
>f2 : <const T, U>(x: T | undefined) => T
|
||||
>{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; }
|
||||
>a : 1
|
||||
>1 : 1
|
||||
>b : "c"
|
||||
>"c" : "c"
|
||||
>d : ["e", 2, true, { f: "g"; }]
|
||||
>["e", 2, true, { f: "g" }] : ["e", 2, true, { f: "g"; }]
|
||||
>"e" : "e"
|
||||
>2 : 2
|
||||
>true : true
|
||||
>{ f: "g" } : { f: "g"; }
|
||||
>f : "g"
|
||||
>"g" : "g"
|
||||
|
||||
declare function f3<const T>(x: T): T[];
|
||||
>f3 : <const T>(x: T) => T[]
|
||||
>x : T
|
||||
|
||||
const x31 = f3("hello");
|
||||
>x31 : "hello"[]
|
||||
>f3("hello") : "hello"[]
|
||||
>f3 : <const T>(x: T) => T[]
|
||||
>"hello" : "hello"
|
||||
|
||||
const x32 = f3("hello");
|
||||
>x32 : "hello"[]
|
||||
>f3("hello") : "hello"[]
|
||||
>f3 : <const T>(x: T) => T[]
|
||||
>"hello" : "hello"
|
||||
|
||||
declare function f4<const T>(obj: [T, T]): T;
|
||||
>f4 : <const T>(obj: [T, T]) => T
|
||||
>obj : [T, T]
|
||||
|
||||
const x41 = f4([[1, 'x'], [2, 'y']]);
|
||||
>x41 : readonly [1, "x"] | readonly [2, "y"]
|
||||
>f4([[1, 'x'], [2, 'y']]) : readonly [1, "x"] | readonly [2, "y"]
|
||||
>f4 : <const T>(obj: [T, T]) => T
|
||||
>[[1, 'x'], [2, 'y']] : [[1, "x"], [2, "y"]]
|
||||
>[1, 'x'] : [1, "x"]
|
||||
>1 : 1
|
||||
>'x' : "x"
|
||||
>[2, 'y'] : [2, "y"]
|
||||
>2 : 2
|
||||
>'y' : "y"
|
||||
|
||||
const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]);
|
||||
>x42 : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; }
|
||||
>f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]) : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; }
|
||||
>f4 : <const T>(obj: [T, T]) => T
|
||||
>[{ a: 1, b: 'x' }, { a: 2, b: 'y' }] : [{ a: 1; b: "x"; }, { a: 2; b: "y"; }]
|
||||
>{ a: 1, b: 'x' } : { a: 1; b: "x"; }
|
||||
>a : 1
|
||||
>1 : 1
|
||||
>b : "x"
|
||||
>'x' : "x"
|
||||
>{ a: 2, b: 'y' } : { a: 2; b: "y"; }
|
||||
>a : 2
|
||||
>2 : 2
|
||||
>b : "y"
|
||||
>'y' : "y"
|
||||
|
||||
declare function f5<const T>(obj: { x: T, y: T }): T;
|
||||
>f5 : <const T>(obj: { x: T; y: T;}) => T
|
||||
>obj : { x: T; y: T; }
|
||||
>x : T
|
||||
>y : T
|
||||
|
||||
const x51 = f5({ x: [1, 'x'], y: [2, 'y'] });
|
||||
>x51 : readonly [1, "x"] | readonly [2, "y"]
|
||||
>f5({ x: [1, 'x'], y: [2, 'y'] }) : readonly [1, "x"] | readonly [2, "y"]
|
||||
>f5 : <const T>(obj: { x: T; y: T; }) => T
|
||||
>{ x: [1, 'x'], y: [2, 'y'] } : { x: [1, "x"]; y: [2, "y"]; }
|
||||
>x : [1, "x"]
|
||||
>[1, 'x'] : [1, "x"]
|
||||
>1 : 1
|
||||
>'x' : "x"
|
||||
>y : [2, "y"]
|
||||
>[2, 'y'] : [2, "y"]
|
||||
>2 : 2
|
||||
>'y' : "y"
|
||||
|
||||
const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } });
|
||||
>x52 : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; }
|
||||
>f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }) : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; }
|
||||
>f5 : <const T>(obj: { x: T; y: T; }) => T
|
||||
>{ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } } : { x: { a: 1; b: "x"; }; y: { a: 2; b: "y"; }; }
|
||||
>x : { a: 1; b: "x"; }
|
||||
>{ a: 1, b: 'x' } : { a: 1; b: "x"; }
|
||||
>a : 1
|
||||
>1 : 1
|
||||
>b : "x"
|
||||
>'x' : "x"
|
||||
>y : { a: 2; b: "y"; }
|
||||
>{ a: 2, b: 'y' } : { a: 2; b: "y"; }
|
||||
>a : 2
|
||||
>2 : 2
|
||||
>b : "y"
|
||||
>'y' : "y"
|
||||
|
||||
declare function f6<const T extends readonly unknown[]>(...args: T): T;
|
||||
>f6 : <const T extends readonly unknown[]>(...args: T) => T
|
||||
>args : T
|
||||
|
||||
const x61 = f6(1, 'b', { a: 1, b: 'x' });
|
||||
>x61 : readonly [1, "b", { readonly a: 1; readonly b: "x"; }]
|
||||
>f6(1, 'b', { a: 1, b: 'x' }) : readonly [1, "b", { readonly a: 1; readonly b: "x"; }]
|
||||
>f6 : <const T extends readonly unknown[]>(...args: T) => T
|
||||
>1 : 1
|
||||
>'b' : "b"
|
||||
>{ a: 1, b: 'x' } : { a: 1; b: "x"; }
|
||||
>a : 1
|
||||
>1 : 1
|
||||
>b : "x"
|
||||
>'x' : "x"
|
||||
|
||||
class C1<const T> {
|
||||
>C1 : C1<T>
|
||||
|
||||
constructor(x: T) {}
|
||||
>x : T
|
||||
|
||||
foo<const U>(x: U) { return x; }
|
||||
>foo : <const U>(x: U) => U
|
||||
>x : U
|
||||
>x : U
|
||||
}
|
||||
|
||||
const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
>c71 : C1<{ readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }>
|
||||
>new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : C1<{ readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }>
|
||||
>C1 : typeof C1
|
||||
>{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; }
|
||||
>a : 1
|
||||
>1 : 1
|
||||
>b : "c"
|
||||
>"c" : "c"
|
||||
>d : ["e", 2, true, { f: "g"; }]
|
||||
>["e", 2, true, { f: "g" }] : ["e", 2, true, { f: "g"; }]
|
||||
>"e" : "e"
|
||||
>2 : 2
|
||||
>true : true
|
||||
>{ f: "g" } : { f: "g"; }
|
||||
>f : "g"
|
||||
>"g" : "g"
|
||||
|
||||
const c72 = c71.foo(['a', ['b', 'c']]);
|
||||
>c72 : readonly ["a", readonly ["b", "c"]]
|
||||
>c71.foo(['a', ['b', 'c']]) : readonly ["a", readonly ["b", "c"]]
|
||||
>c71.foo : <const U>(x: U) => U
|
||||
>c71 : C1<{ readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }>
|
||||
>foo : <const U>(x: U) => U
|
||||
>['a', ['b', 'c']] : ["a", ["b", "c"]]
|
||||
>'a' : "a"
|
||||
>['b', 'c'] : ["b", "c"]
|
||||
>'b' : "b"
|
||||
>'c' : "c"
|
||||
|
||||
const fx1 = <const T>(x: T) => x;
|
||||
>fx1 : <const T>(x: T) => T
|
||||
><const T>(x: T) => x : <const T>(x: T) => T
|
||||
>x : T
|
||||
>x : T
|
||||
|
||||
const fx2 = <const T,>(x: T) => x;
|
||||
>fx2 : <const T>(x: T) => T
|
||||
><const T,>(x: T) => x : <const T>(x: T) => T
|
||||
>x : T
|
||||
>x : T
|
||||
|
||||
interface I1<const T> { x: T } // Error
|
||||
>x : T
|
||||
|
||||
interface I2 {
|
||||
f<const T>(x: T): T;
|
||||
>f : <const T>(x: T) => T
|
||||
>x : T
|
||||
}
|
||||
|
||||
type T1<const T> = T; // Error
|
||||
>T1 : T
|
||||
|
||||
type T2 = <const T>(x: T) => T;
|
||||
>T2 : <const T>(x: T) => T
|
||||
>x : T
|
||||
|
||||
type T3 = { <const T>(x: T): T };
|
||||
>T3 : <const T>(x: T) => T
|
||||
>x : T
|
||||
|
||||
type T4 = new <const T>(x: T) => T;
|
||||
>T4 : new <const T>(x: T) => T
|
||||
>x : T
|
||||
|
||||
type T5 = { new <const T>(x: T): T };
|
||||
>T5 : new <const T>(x: T) => T
|
||||
>x : T
|
||||
|
||||
// Corrected repro from #51745
|
||||
|
||||
type Obj = { a: { b: { c: "123" } } };
|
||||
>Obj : { a: { b: { c: "123"; };}; }
|
||||
>a : { b: { c: "123";}; }
|
||||
>b : { c: "123"; }
|
||||
>c : "123"
|
||||
|
||||
type GetPath<T, P> =
|
||||
>GetPath : GetPath<T, P>
|
||||
|
||||
P extends readonly [] ? T :
|
||||
P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath<T[A], Rest> :
|
||||
never;
|
||||
|
||||
function set<T, const P extends readonly string[]>(obj: T, path: P, value: GetPath<T, P>) {}
|
||||
>set : <T, const P extends readonly string[]>(obj: T, path: P, value: GetPath<T, P>) => void
|
||||
>obj : T
|
||||
>path : P
|
||||
>value : GetPath<T, P>
|
||||
|
||||
declare let obj: Obj;
|
||||
>obj : Obj
|
||||
|
||||
declare let value: "123";
|
||||
>value : "123"
|
||||
|
||||
set(obj, ['a', 'b', 'c'], value);
|
||||
>set(obj, ['a', 'b', 'c'], value) : void
|
||||
>set : <T, const P extends readonly string[]>(obj: T, path: P, value: GetPath<T, P>) => void
|
||||
>obj : Obj
|
||||
>['a', 'b', 'c'] : ["a", "b", "c"]
|
||||
>'a' : "a"
|
||||
>'b' : "b"
|
||||
>'c' : "c"
|
||||
>value : "123"
|
||||
|
||||
@ -0,0 +1,72 @@
|
||||
// @strict: true
|
||||
|
||||
declare function f1<const T>(x: T): T;
|
||||
|
||||
const x11 = f1('a');
|
||||
const x12 = f1(['a', ['b', 'c']]);
|
||||
const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
|
||||
declare function f2<const T, U>(x: T | undefined): T;
|
||||
|
||||
const x21 = f2('a');
|
||||
const x22 = f2(['a', ['b', 'c']]);
|
||||
const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
|
||||
declare function f3<const T>(x: T): T[];
|
||||
|
||||
const x31 = f3("hello");
|
||||
const x32 = f3("hello");
|
||||
|
||||
declare function f4<const T>(obj: [T, T]): T;
|
||||
|
||||
const x41 = f4([[1, 'x'], [2, 'y']]);
|
||||
const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]);
|
||||
|
||||
declare function f5<const T>(obj: { x: T, y: T }): T;
|
||||
|
||||
const x51 = f5({ x: [1, 'x'], y: [2, 'y'] });
|
||||
const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } });
|
||||
|
||||
declare function f6<const T extends readonly unknown[]>(...args: T): T;
|
||||
|
||||
const x61 = f6(1, 'b', { a: 1, b: 'x' });
|
||||
|
||||
class C1<const T> {
|
||||
constructor(x: T) {}
|
||||
foo<const U>(x: U) { return x; }
|
||||
}
|
||||
|
||||
const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] });
|
||||
const c72 = c71.foo(['a', ['b', 'c']]);
|
||||
|
||||
const fx1 = <const T>(x: T) => x;
|
||||
const fx2 = <const T,>(x: T) => x;
|
||||
|
||||
interface I1<const T> { x: T } // Error
|
||||
|
||||
interface I2 {
|
||||
f<const T>(x: T): T;
|
||||
}
|
||||
|
||||
type T1<const T> = T; // Error
|
||||
|
||||
type T2 = <const T>(x: T) => T;
|
||||
type T3 = { <const T>(x: T): T };
|
||||
type T4 = new <const T>(x: T) => T;
|
||||
type T5 = { new <const T>(x: T): T };
|
||||
|
||||
// Corrected repro from #51745
|
||||
|
||||
type Obj = { a: { b: { c: "123" } } };
|
||||
|
||||
type GetPath<T, P> =
|
||||
P extends readonly [] ? T :
|
||||
P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath<T[A], Rest> :
|
||||
never;
|
||||
|
||||
function set<T, const P extends readonly string[]>(obj: T, path: P, value: GetPath<T, P>) {}
|
||||
|
||||
declare let obj: Obj;
|
||||
declare let value: "123";
|
||||
|
||||
set(obj, ['a', 'b', 'c'], value);
|
||||
Loading…
x
Reference in New Issue
Block a user