mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Adds additional logic to determine how to emit a type reference for decorator metadata
This commit is contained in:
+54
-7
@@ -3306,6 +3306,15 @@ namespace ts {
|
||||
return getSignaturesOfObjectOrUnionType(getApparentType(type), kind);
|
||||
}
|
||||
|
||||
function typeHasConstructSignatures(type: Type): boolean {
|
||||
let apparentType = getApparentType(type);
|
||||
if (apparentType.flags & (TypeFlags.ObjectType | TypeFlags.Union)) {
|
||||
let resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
|
||||
return resolved.constructSignatures.length > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function typeHasCallOrConstructSignatures(type: Type): boolean {
|
||||
let apparentType = getApparentType(type);
|
||||
if (apparentType.flags & (TypeFlags.ObjectType | TypeFlags.Union)) {
|
||||
@@ -13207,15 +13216,53 @@ namespace ts {
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isFunctionType(type: Type): boolean {
|
||||
return type.flags & TypeFlags.ObjectType && getSignaturesOfType(type, SignatureKind.Call).length > 0;
|
||||
}
|
||||
|
||||
function isTypeReferenceWithValueDeclaration(node: TypeReferenceNode): boolean {
|
||||
function isTypeWithValue(node: TypeReferenceNode): TypeWithValueResolutionResult {
|
||||
// Resolve the symbol as a value to ensure the type can be reached at runtime during emit.
|
||||
let symbol = resolveEntityName(node.typeName, SymbolFlags.Value, /*ignoreErrors*/ true);
|
||||
if (symbol.valueDeclaration) {
|
||||
let type = getTypeOfSymbol(symbol);
|
||||
return typeHasCallOrConstructSignatures(type);
|
||||
let constructorType = symbol ? getTypeOfSymbol(symbol) : undefined;
|
||||
if (constructorType && isConstructorType(constructorType)) {
|
||||
return TypeWithValueResolutionResult.ConstructorTypeWithValue;
|
||||
}
|
||||
|
||||
let type = getTypeFromTypeNode(node);
|
||||
if (type === unknownType) {
|
||||
return TypeWithValueResolutionResult.Unknown;
|
||||
}
|
||||
else if (type.flags & TypeFlags.Any) {
|
||||
return TypeWithValueResolutionResult.ObjectType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.Void)) {
|
||||
return TypeWithValueResolutionResult.VoidType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.Boolean)) {
|
||||
return TypeWithValueResolutionResult.BooleanType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.NumberLike)) {
|
||||
return TypeWithValueResolutionResult.NumberType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.StringLike)) {
|
||||
return TypeWithValueResolutionResult.StringType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.Tuple)) {
|
||||
return TypeWithValueResolutionResult.ArrayType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.ESSymbol)) {
|
||||
return TypeWithValueResolutionResult.ESSymbolType;
|
||||
}
|
||||
else if (isFunctionType(type)) {
|
||||
return TypeWithValueResolutionResult.FunctionType;
|
||||
}
|
||||
else if (isArrayType(type)) {
|
||||
return TypeWithValueResolutionResult.ArrayType;
|
||||
}
|
||||
else {
|
||||
return TypeWithValueResolutionResult.ObjectType;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) {
|
||||
@@ -13315,7 +13362,7 @@ namespace ts {
|
||||
collectLinkedAliases,
|
||||
getBlockScopedVariableId,
|
||||
getReferencedValueDeclaration,
|
||||
isTypeReferenceWithValueDeclaration,
|
||||
isTypeWithValue,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+54
-7
@@ -4710,13 +4710,59 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
/** Serializes a TypeReferenceNode to an appropriate JS constructor value. Used by the __metadata decorator. */
|
||||
function emitSerializedTypeReferenceNode(node: TypeReferenceNode) {
|
||||
let typeName = node.typeName;
|
||||
if (resolver.isTypeReferenceWithValueDeclaration(node)) {
|
||||
emitEntityNameAsExpression(typeName, /*useFallback*/ false);
|
||||
}
|
||||
else {
|
||||
write("(");
|
||||
emitEntityNameAsExpression(typeName, /*useFallback*/ true);
|
||||
write(") || Object");
|
||||
let result = resolver.isTypeWithValue(node);
|
||||
switch (result) {
|
||||
case TypeWithValueResolutionResult.Unknown:
|
||||
let temp = createAndRecordTempVariable(TempFlags.Auto);
|
||||
write("(typeof (");
|
||||
emitNodeWithoutSourceMap(temp);
|
||||
write(" = ")
|
||||
emitEntityNameAsExpression(typeName, /*useFallback*/ true);
|
||||
write(") === 'function' && ");
|
||||
emitNodeWithoutSourceMap(temp);
|
||||
write(") || Object");
|
||||
break;
|
||||
|
||||
case TypeWithValueResolutionResult.ConstructorTypeWithValue:
|
||||
emitEntityNameAsExpression(typeName, /*useFallback*/ false);
|
||||
break;
|
||||
|
||||
case TypeWithValueResolutionResult.VoidType:
|
||||
write("void 0");
|
||||
break;
|
||||
|
||||
case TypeWithValueResolutionResult.BooleanType:
|
||||
write("Boolean");
|
||||
break;
|
||||
|
||||
case TypeWithValueResolutionResult.NumberType:
|
||||
write("Number");
|
||||
break;
|
||||
|
||||
case TypeWithValueResolutionResult.StringType:
|
||||
write("String");
|
||||
break;
|
||||
|
||||
case TypeWithValueResolutionResult.ArrayType:
|
||||
write("Array");
|
||||
break;
|
||||
|
||||
case TypeWithValueResolutionResult.ESSymbolType:
|
||||
if (languageVersion < ScriptTarget.ES6) {
|
||||
write("typeof Symbol === 'function' ? Symbol : Object");
|
||||
}
|
||||
else {
|
||||
write("Symbol");
|
||||
}
|
||||
break;
|
||||
|
||||
case TypeWithValueResolutionResult.FunctionType:
|
||||
write("Function");
|
||||
break;
|
||||
|
||||
case TypeWithValueResolutionResult.ObjectType:
|
||||
write("Object");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5927,6 +5973,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
Debug.assert(!exportFunctionForFile);
|
||||
// make sure that name of 'exports' function does not conflict with existing identifiers
|
||||
exportFunctionForFile = makeUniqueName("exports");
|
||||
writeLine();
|
||||
write("System.register(");
|
||||
if (node.moduleName) {
|
||||
write(`"${node.moduleName}", `);
|
||||
|
||||
+15
-1
@@ -1501,6 +1501,20 @@ namespace ts {
|
||||
export interface SymbolAccessiblityResult extends SymbolVisibilityResult {
|
||||
errorModuleName?: string // If the symbol is not visible from module, module's name
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export enum TypeWithValueResolutionResult {
|
||||
Unknown,
|
||||
ConstructorTypeWithValue,
|
||||
VoidType,
|
||||
NumberType,
|
||||
StringType,
|
||||
BooleanType,
|
||||
ArrayType,
|
||||
ESSymbolType,
|
||||
FunctionType,
|
||||
ObjectType,
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface EmitResolver {
|
||||
@@ -1525,7 +1539,7 @@ namespace ts {
|
||||
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
|
||||
getBlockScopedVariableId(node: Identifier): number;
|
||||
getReferencedValueDeclaration(reference: Identifier): Declaration;
|
||||
isTypeReferenceWithValueDeclaration(node: TypeReferenceNode): boolean;
|
||||
isTypeWithValue(node: TypeReferenceNode): TypeWithValueResolutionResult;
|
||||
}
|
||||
|
||||
export const enum SymbolFlags {
|
||||
|
||||
Reference in New Issue
Block a user