Support 'readonly' type modifier on array and tuple types

This commit is contained in:
Anders Hejlsberg 2019-01-15 09:43:39 -08:00
parent 903863a87a
commit bb8378fddf
5 changed files with 31 additions and 11 deletions

View file

@ -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) {

View file

@ -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",

View file

@ -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);

View file

@ -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();

View file

@ -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;
}