-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow extending from any #14935
Allow extending from any #14935
Conversation
Extending from any adds an index signature: [s: string]: any to both the instance and static sides of the class.
Also improve how the string indexer for any-inheriting types is added.
} | ||
|
||
let c = new C(); | ||
c.known.length; // error, 'real' has no 'length' property |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
real / sreal
@yuit @andy-ms mind taking a look? |
src/compiler/checker.ts
Outdated
@@ -4617,7 +4617,7 @@ namespace ts { | |||
error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol)); | |||
return type.resolvedBaseConstructorType = unknownType; | |||
} | |||
if (baseConstructorType !== unknownType && baseConstructorType !== nullWideningType && !isConstructorType(baseConstructorType)) { | |||
if (baseConstructorType !== anyType && baseConstructorType !== unknownType && baseConstructorType !== nullWideningType && !isConstructorType(baseConstructorType)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard for me to look up right now whether unknownType
includes it, could you check for TypeFlags.Any
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just check unknownType
and anyType
both have TypeFlags.Any
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Includes anyType, autoType, unknownType. Seems like it should work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/compiler/checker.ts
Outdated
// object types. | ||
function isValidBaseType(type: Type): boolean { | ||
return type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive) && !isGenericMappedType(type) || | ||
return !!(type.flags & TypeFlags.Any) || | ||
type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive) && !isGenericMappedType(type) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this just be type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should work, although it's kind of a weird pun in that we rely on !isGenericMappedType(anyType)
being true.
src/compiler/checker.ts
Outdated
@@ -5130,7 +5134,9 @@ namespace ts { | |||
addInheritedMembers(members, getPropertiesOfType(instantiatedBaseType)); | |||
callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call)); | |||
constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct)); | |||
stringIndexInfo = stringIndexInfo || getIndexInfoOfType(instantiatedBaseType, IndexKind.String); | |||
stringIndexInfo = stringIndexInfo || (instantiatedBaseType === anyType ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: would it be easier to read this way:
if (!stringIndexInfo) {
stringIndexInfo = instantiatedBaseType === anyType ? createIndexInfo(anyType, /*isReadonly*/ false) : getIndexInfoOfType(instantiatedBaseType, IndexKind.String);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess so. Done.
I wonder if anything from #12352 could be simplified now. |
src/compiler/checker.ts
Outdated
@@ -4662,6 +4662,9 @@ namespace ts { | |||
// type arguments in the same manner as a type reference to get the same error reporting experience. | |||
baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol); | |||
} | |||
else if (baseConstructorType.flags & TypeFlags.Any) { | |||
baseType = anyType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you leave a comment saying why it is necessary to set it to anyType
instead of baseConstructorType
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no good reason; in fact it reduces test churn to return baseConstructorType for tests that extend undefined variables, which I think get unknownType
instead of anyType
, meaning that you get slightly more errors.
I'll change it to baseConstructorType.
Returns several baselines to their original states.
@andy-ms Maybe? I don't understand the differences between using Seems like it would be worth reverting #12352 to see how it behaves, because I'm not able to predict much about module behaviour a priori. |
OK, we can try reverting #12352 later.
|
Extending symbols from untyped modules is no longer an error, so #12532 didn't get us anything except slightly better quick info.
Reverting #12352 turned out to be straightforward, so I ended up merging that branch back into this PR. |
@@ -1333,7 +1331,7 @@ namespace ts { | |||
if (targetSymbol) { | |||
const name = specifier.propertyName || specifier.name; | |||
if (name.text) { | |||
if (isUntypedOrShorthandAmbientModuleSymbol(moduleSymbol)) { | |||
if (isShorthandAmbientModuleSymbol(moduleSymbol)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the old name better, even if it's a bit long.
Test asserts that unused locals error works for untyped modules. Comment no longer claims to check for untyped modules.
Extending from any adds an index signature: [s: string]: any to both the
instance and static sides of the class.
Fixes #14301
Fixes #15040