mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-17 12:19:32 -05:00
Support 'this: readonly' parameter declarations
This commit is contained in:
@@ -256,6 +256,7 @@ namespace ts {
|
||||
const neverType = createIntrinsicType(TypeFlags.Never, "never");
|
||||
const silentNeverType = createIntrinsicType(TypeFlags.Never, "never");
|
||||
const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object");
|
||||
const readonlyThisType = createIntrinsicType(TypeFlags.Any, "readonly");
|
||||
|
||||
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||
|
||||
@@ -5675,11 +5676,37 @@ namespace ts {
|
||||
return indexInfo && !indexInfo.isReadonly ? createIndexInfo(indexInfo.type, true, indexInfo.declaration) : indexInfo;
|
||||
}
|
||||
|
||||
function hasReadonlyThisParameter(sig: SignatureDeclaration) {
|
||||
const param = firstOrUndefined(sig.parameters);
|
||||
return param &&
|
||||
param.name.kind === SyntaxKind.Identifier &&
|
||||
(<Identifier>param.name).text === "this" &&
|
||||
param.type &&
|
||||
param.type.kind === SyntaxKind.ReadonlyKeyword;
|
||||
}
|
||||
|
||||
function isReadonlyThisMethod(symbol: Symbol) {
|
||||
if (symbol.flags & SymbolFlags.Method) {
|
||||
for (let i = 0; i < symbol.declarations.length; i++) {
|
||||
const node = symbol.declarations[i];
|
||||
if (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) {
|
||||
if (!hasReadonlyThisParameter(<SignatureDeclaration>node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function resolveReadonlyTypeMembers(type: ReadonlyObjectType) {
|
||||
const target = type.type;
|
||||
const members = createMap<Symbol>() as SymbolTable;
|
||||
for (const symbol of getPropertiesOfObjectType(target)) {
|
||||
members.set(symbol.name, instantiateSymbol(symbol, identityMapper, /*readonly*/ true));
|
||||
if (!(symbol.flags & SymbolFlags.Method) || isReadonlyThisMethod(symbol)) {
|
||||
members.set(symbol.name, instantiateSymbol(symbol, identityMapper, /*readonly*/ true));
|
||||
}
|
||||
}
|
||||
const callSignatures = getSignaturesOfType(target, SignatureKind.Call);
|
||||
const constructSignatures = getSignaturesOfType(target, SignatureKind.Construct);
|
||||
@@ -6546,7 +6573,8 @@ namespace ts {
|
||||
|
||||
function getThisTypeOfSignature(signature: Signature): Type | undefined {
|
||||
if (signature.thisParameter) {
|
||||
return getTypeOfSymbol(signature.thisParameter);
|
||||
const type = getTypeOfSymbol(signature.thisParameter);
|
||||
return type !== readonlyThisType ? type : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7924,6 +7952,8 @@ namespace ts {
|
||||
return neverType;
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
return nonPrimitiveType;
|
||||
case SyntaxKind.ReadonlyKeyword:
|
||||
return readonlyThisType;
|
||||
case SyntaxKind.ThisType:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
return getTypeFromThisTypeNode(node);
|
||||
@@ -12410,9 +12440,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (isClassLike(container.parent)) {
|
||||
const symbol = getSymbolOfNode(container.parent);
|
||||
const type = hasModifier(container, ModifierFlags.Static) ? getTypeOfSymbol(symbol) : (<InterfaceType>getDeclaredTypeOfSymbol(symbol)).thisType;
|
||||
return getFlowTypeOfReference(node, type);
|
||||
const classSymbol = getSymbolOfNode(container.parent);
|
||||
const type = hasModifier(container, ModifierFlags.Static) ? getTypeOfSymbol(classSymbol) : (<InterfaceType>getDeclaredTypeOfSymbol(classSymbol)).thisType;
|
||||
return getFlowTypeOfReference(node, isReadonlyThisMethod(getSymbolOfNode(container)) ? getReadonlyType(type) : type);
|
||||
}
|
||||
|
||||
if (isInJavaScriptFile(node)) {
|
||||
|
||||
@@ -2153,8 +2153,16 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function parseParameterType(): TypeNode {
|
||||
function nextTokenIsStartOfType() {
|
||||
nextToken();
|
||||
return isStartOfType();
|
||||
}
|
||||
|
||||
function parseParameterType(allowReadonly: boolean): TypeNode {
|
||||
if (parseOptional(SyntaxKind.ColonToken)) {
|
||||
if (allowReadonly && token() === SyntaxKind.ReadonlyKeyword && !lookAhead(nextTokenIsStartOfType)) {
|
||||
return parseTokenNode<TypeNode>();
|
||||
}
|
||||
return parseType();
|
||||
}
|
||||
|
||||
@@ -2169,7 +2177,7 @@ namespace ts {
|
||||
const node = <ParameterDeclaration>createNode(SyntaxKind.Parameter);
|
||||
if (token() === SyntaxKind.ThisKeyword) {
|
||||
node.name = createIdentifier(/*isIdentifier*/ true);
|
||||
node.type = parseParameterType();
|
||||
node.type = parseParameterType(/*allowReadonly*/ true);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
@@ -2193,7 +2201,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
|
||||
node.type = parseParameterType();
|
||||
node.type = parseParameterType(/*allowReadonly*/ false);
|
||||
node.initializer = parseBindingElementInitializer(/*inParameter*/ true);
|
||||
|
||||
// Do not check for initializers in an ambient context for parameters. This is not
|
||||
|
||||
@@ -3351,11 +3351,6 @@ namespace ts {
|
||||
type: ObjectType;
|
||||
}
|
||||
|
||||
// Readonly type variable (TypeFlags.Readonly)
|
||||
export interface ReadonlyTypeVariable extends Type {
|
||||
type: TypeVariable;
|
||||
}
|
||||
|
||||
export interface EvolvingArrayType extends ObjectType {
|
||||
elementType: Type; // Element expressions of evolving array type
|
||||
finalArrayType?: Type; // Final array type of evolving array type
|
||||
@@ -3425,6 +3420,11 @@ namespace ts {
|
||||
constraint?: Type;
|
||||
}
|
||||
|
||||
// Readonly type variable (TypeFlags.Readonly)
|
||||
export interface ReadonlyTypeVariable extends TypeVariable {
|
||||
type: TypeVariable;
|
||||
}
|
||||
|
||||
// keyof T types (TypeFlags.Index)
|
||||
export interface IndexType extends Type {
|
||||
type: TypeVariable | UnionOrIntersectionType;
|
||||
|
||||
Reference in New Issue
Block a user