Support 'readonly' type modifier on array and tuple types
This commit is contained in:
parent
903863a87a
commit
bb8378fddf
5 changed files with 31 additions and 11 deletions
|
@ -3592,14 +3592,15 @@ namespace ts {
|
|||
|
||||
function typeReferenceToTypeNode(type: TypeReference) {
|
||||
const typeArguments: ReadonlyArray<Type> = type.typeArguments || emptyArray;
|
||||
if (type.target === globalArrayType) {
|
||||
if (type.target === globalArrayType || type.target === globalReadonlyArrayType) {
|
||||
if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) {
|
||||
const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context);
|
||||
return createTypeReferenceNode("Array", [typeArgumentNode]);
|
||||
return createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]);
|
||||
}
|
||||
|
||||
const elementType = typeToTypeNodeHelper(typeArguments[0], context);
|
||||
return createArrayTypeNode(elementType);
|
||||
const arrayType = createArrayTypeNode(elementType);
|
||||
return type.target === globalArrayType ? arrayType : createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType);
|
||||
}
|
||||
else if (type.target.objectFlags & ObjectFlags.Tuple) {
|
||||
if (typeArguments.length > 0) {
|
||||
|
@ -3613,11 +3614,12 @@ namespace ts {
|
|||
createOptionalTypeNode(tupleConstituentNodes[i]);
|
||||
}
|
||||
const tupleTypeNode = createTupleTypeNode(tupleConstituentNodes);
|
||||
return (<TupleType>type.target).readonly ? createTypeReferenceNode("Readonly", [tupleTypeNode]) : tupleTypeNode;
|
||||
return (<TupleType>type.target).readonly ? createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode;
|
||||
}
|
||||
}
|
||||
if (context.encounteredError || (context.flags & NodeBuilderFlags.AllowEmptyTuple)) {
|
||||
return createTupleTypeNode([]);
|
||||
const tupleTypeNode = createTupleTypeNode([]);
|
||||
return (<TupleType>type.target).readonly ? createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode;
|
||||
}
|
||||
context.encounteredError = true;
|
||||
return undefined!; // TODO: GH#18217
|
||||
|
@ -9030,11 +9032,15 @@ namespace ts {
|
|||
function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = createArrayType(getTypeFromTypeNode(node.elementType));
|
||||
links.resolvedType = createArrayType(getTypeFromTypeNode(node.elementType), isReadonlyTypeOperator(node.parent));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function isReadonlyTypeOperator(node: Node) {
|
||||
return isTypeOperatorNode(node) && node.operator === SyntaxKind.ReadonlyKeyword;
|
||||
}
|
||||
|
||||
// We represent tuple types as type references to synthesized generic interface types created by
|
||||
// this function. The types are of the form:
|
||||
//
|
||||
|
@ -9114,7 +9120,7 @@ namespace ts {
|
|||
const type = getTypeFromTypeNode(n);
|
||||
return n === restElement && getIndexTypeOfType(type, IndexKind.Number) || type;
|
||||
});
|
||||
links.resolvedType = createTupleType(elementTypes, minLength, !!restElement);
|
||||
links.resolvedType = createTupleType(elementTypes, minLength, !!restElement, isReadonlyTypeOperator(node.parent));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
@ -9667,6 +9673,9 @@ namespace ts {
|
|||
? getESSymbolLikeTypeForNode(walkUpParenthesizedTypes(node.parent))
|
||||
: errorType;
|
||||
break;
|
||||
case SyntaxKind.ReadonlyKeyword:
|
||||
links.resolvedType = getTypeFromTypeNode(node.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return links.resolvedType!; // TODO: GH#18217
|
||||
|
@ -30513,6 +30522,11 @@ namespace ts {
|
|||
return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_here);
|
||||
}
|
||||
}
|
||||
else if (node.operator === SyntaxKind.ReadonlyKeyword) {
|
||||
if (node.type.kind !== SyntaxKind.ArrayType && node.type.kind !== SyntaxKind.TupleType) {
|
||||
return grammarErrorOnFirstToken(node, Diagnostics.readonly_type_modifier_is_only_permitted_on_array_and_typle_types, tokenToString(SyntaxKind.SymbolKeyword));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkGrammarForInvalidDynamicName(node: DeclarationName, message: DiagnosticMessage) {
|
||||
|
|
|
@ -1023,6 +1023,10 @@
|
|||
"category": "Error",
|
||||
"code": 1353
|
||||
},
|
||||
"'readonly' type modifier is only permitted on array and typle types.": {
|
||||
"category": "Error",
|
||||
"code": 1354
|
||||
},
|
||||
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
|
|
|
@ -876,8 +876,8 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function createTypeOperatorNode(type: TypeNode): TypeOperatorNode;
|
||||
export function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword, type: TypeNode): TypeOperatorNode;
|
||||
export function createTypeOperatorNode(operatorOrType: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | TypeNode, type?: TypeNode) {
|
||||
export function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode;
|
||||
export function createTypeOperatorNode(operatorOrType: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | TypeNode, type?: TypeNode) {
|
||||
const node = createSynthesizedNode(SyntaxKind.TypeOperator) as TypeOperatorNode;
|
||||
node.operator = typeof operatorOrType === "number" ? operatorOrType : SyntaxKind.KeyOfKeyword;
|
||||
node.type = parenthesizeElementTypeMember(typeof operatorOrType === "number" ? type! : operatorOrType);
|
||||
|
|
|
@ -2962,6 +2962,7 @@ namespace ts {
|
|||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.BigIntKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.ReadonlyKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.UniqueKeyword:
|
||||
case SyntaxKind.VoidKeyword:
|
||||
|
@ -3051,7 +3052,7 @@ namespace ts {
|
|||
return finishNode(postfix);
|
||||
}
|
||||
|
||||
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword) {
|
||||
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) {
|
||||
const node = <TypeOperatorNode>createNode(SyntaxKind.TypeOperator);
|
||||
parseExpected(operator);
|
||||
node.operator = operator;
|
||||
|
@ -3073,6 +3074,7 @@ namespace ts {
|
|||
switch (operator) {
|
||||
case SyntaxKind.KeyOfKeyword:
|
||||
case SyntaxKind.UniqueKeyword:
|
||||
case SyntaxKind.ReadonlyKeyword:
|
||||
return parseTypeOperator(operator);
|
||||
case SyntaxKind.InferKeyword:
|
||||
return parseInferType();
|
||||
|
|
|
@ -1233,7 +1233,7 @@ namespace ts {
|
|||
|
||||
export interface TypeOperatorNode extends TypeNode {
|
||||
kind: SyntaxKind.TypeOperator;
|
||||
operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword;
|
||||
operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword;
|
||||
type: TypeNode;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue