mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 19:16:17 -06:00
Support parametric property access expressions + some renaming
This commit is contained in:
parent
c21592ede1
commit
e7cfbfe185
@ -3067,7 +3067,7 @@ namespace ts {
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.ThisType:
|
||||
case SyntaxKind.TypeOperator:
|
||||
case SyntaxKind.PropertyAccessType:
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
case SyntaxKind.LiteralType:
|
||||
// Types and signatures are TypeScript syntax, and exclude all other facts.
|
||||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
|
||||
@ -2219,15 +2219,15 @@ namespace ts {
|
||||
else if (type.flags & TypeFlags.StringOrNumberLiteral) {
|
||||
writer.writeStringLiteral(literalTypeToString(<LiteralType>type));
|
||||
}
|
||||
else if (type.flags & TypeFlags.PropertyName) {
|
||||
else if (type.flags & TypeFlags.Index) {
|
||||
writer.writeKeyword("keyof");
|
||||
writeSpace(writer);
|
||||
writeType((<PropertyNameType>type).type, TypeFormatFlags.InElementType);
|
||||
writeType((<IndexType>type).type, TypeFormatFlags.InElementType);
|
||||
}
|
||||
else if (type.flags & TypeFlags.PropertyAccess) {
|
||||
writeType((<PropertyAccessType>type).objectType, TypeFormatFlags.InElementType);
|
||||
else if (type.flags & TypeFlags.IndexedAccess) {
|
||||
writeType((<IndexedAccessType>type).objectType, TypeFormatFlags.InElementType);
|
||||
writePunctuation(writer, SyntaxKind.OpenBracketToken);
|
||||
writeType((<PropertyAccessType>type).keyType, TypeFormatFlags.None);
|
||||
writeType((<IndexedAccessType>type).indexType, TypeFormatFlags.None);
|
||||
writePunctuation(writer, SyntaxKind.CloseBracketToken);
|
||||
}
|
||||
else {
|
||||
@ -5678,43 +5678,43 @@ namespace ts {
|
||||
return startsWith(prop.name, "__@") ? neverType : getLiteralTypeForText(TypeFlags.StringLiteral, unescapeIdentifier(prop.name));
|
||||
}
|
||||
|
||||
function getPropertyNameTypeForTypeParameter(type: TypeParameter) {
|
||||
if (!type.resolvedPropertyNameType) {
|
||||
type.resolvedPropertyNameType = <PropertyNameType>createType(TypeFlags.PropertyName);
|
||||
type.resolvedPropertyNameType.type = type;
|
||||
function getIndexTypeForTypeParameter(type: TypeParameter) {
|
||||
if (!type.resolvedIndexType) {
|
||||
type.resolvedIndexType = <IndexType>createType(TypeFlags.Index);
|
||||
type.resolvedIndexType.type = type;
|
||||
}
|
||||
return type.resolvedPropertyNameType;
|
||||
return type.resolvedIndexType;
|
||||
}
|
||||
|
||||
function getPropertyNameType(type: Type): Type {
|
||||
function getIndexType(type: Type): Type {
|
||||
return type.flags & TypeFlags.TypeParameter ?
|
||||
getPropertyNameTypeForTypeParameter(<TypeParameter>type) :
|
||||
getIndexTypeForTypeParameter(<TypeParameter>type) :
|
||||
getUnionType(map(getPropertiesOfType(type), getLiteralTypeFromPropertyName));
|
||||
}
|
||||
|
||||
function getTypeFromTypeOperatorNode(node: TypeOperatorNode) {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = getPropertyNameType(getTypeFromTypeNodeNoAlias(node.type));
|
||||
links.resolvedType = getIndexType(getTypeFromTypeNodeNoAlias(node.type));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function createPropertyAccessType(objectType: Type, keyType: TypeParameter) {
|
||||
const type = <PropertyAccessType>createType(TypeFlags.PropertyAccess);
|
||||
function createIndexedAccessType(objectType: Type, keyType: TypeParameter) {
|
||||
const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
|
||||
type.objectType = objectType;
|
||||
type.keyType = keyType;
|
||||
type.indexType = keyType;
|
||||
return type;
|
||||
}
|
||||
|
||||
function getPropertyAccessTypeForTypeParameter(objectType: Type, keyType: TypeParameter) {
|
||||
const propertyAccessTypes = keyType.resolvedPropertyAccessTypes || (keyType.resolvedPropertyAccessTypes = []);
|
||||
return propertyAccessTypes[objectType.id] || (propertyAccessTypes[objectType.id] = createPropertyAccessType(objectType, keyType));
|
||||
function getIndexedAccessTypeForTypeParameter(objectType: Type, keyType: TypeParameter) {
|
||||
const indexedAccessTypes = keyType.resolvedIndexedAccessTypes || (keyType.resolvedIndexedAccessTypes = []);
|
||||
return indexedAccessTypes[objectType.id] || (indexedAccessTypes[objectType.id] = createIndexedAccessType(objectType, keyType));
|
||||
}
|
||||
|
||||
function getPropertyAccessType(objectType: Type, keyType: Type) {
|
||||
function getIndexedAccessType(objectType: Type, keyType: Type) {
|
||||
if (keyType.flags & TypeFlags.TypeParameter) {
|
||||
return getPropertyAccessTypeForTypeParameter(objectType, <TypeParameter>keyType);
|
||||
return getIndexedAccessTypeForTypeParameter(objectType, <TypeParameter>keyType);
|
||||
}
|
||||
if (isTypeOfKind(keyType, TypeFlags.StringLiteral) && !(keyType.flags & TypeFlags.Intersection)) {
|
||||
return mapType(keyType, t => getTypeOfPropertyOfType(objectType, escapeIdentifier((<LiteralType>t).text)) || unknownType);
|
||||
@ -5722,29 +5722,29 @@ namespace ts {
|
||||
return keyType.flags & TypeFlags.Any ? anyType : unknownType;
|
||||
}
|
||||
|
||||
function resolvePropertyAccessTypeNode(node: PropertyAccessTypeNode) {
|
||||
function resolveIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
|
||||
const objectType = getTypeFromTypeNodeNoAlias(node.objectType);
|
||||
const keyType = getTypeFromTypeNodeNoAlias(node.keyType);
|
||||
const keyType = getTypeFromTypeNodeNoAlias(node.indexType);
|
||||
if (keyType.flags & TypeFlags.TypeParameter &&
|
||||
getConstraintOfTypeParameter(<TypeParameter>keyType) === getPropertyNameType(objectType)) {
|
||||
return getPropertyAccessType(objectType, keyType);
|
||||
getConstraintOfTypeParameter(<TypeParameter>keyType) === getIndexType(objectType)) {
|
||||
return getIndexedAccessType(objectType, keyType);
|
||||
}
|
||||
if (isTypeOfKind(keyType, TypeFlags.StringLiteral) && !(keyType.flags & TypeFlags.Intersection)) {
|
||||
const missing = forEachType(keyType, t => getTypeOfPropertyOfType(objectType, escapeIdentifier((<LiteralType>t).text)) ? undefined : (<LiteralType>t).text);
|
||||
if (missing) {
|
||||
error(node.keyType, Diagnostics.Property_0_is_missing_in_type_1, missing, typeToString(objectType));
|
||||
error(node.indexType, Diagnostics.Property_0_is_missing_in_type_1, missing, typeToString(objectType));
|
||||
return unknownType;
|
||||
}
|
||||
return getPropertyAccessType(objectType, keyType);
|
||||
return getIndexedAccessType(objectType, keyType);
|
||||
}
|
||||
error(node.keyType, Diagnostics.Property_access_element_type_must_be_a_string_literal_type_or_a_type_parameter_constrained_to_keyof_0, typeToString(objectType));
|
||||
error(node.indexType, Diagnostics.Property_access_element_type_must_be_a_string_literal_type_or_a_type_parameter_constrained_to_keyof_0, typeToString(objectType));
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
function getTypeFromPropertyAccessTypeNode(node: PropertyAccessTypeNode) {
|
||||
function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = resolvePropertyAccessTypeNode(node);
|
||||
links.resolvedType = resolveIndexedAccessTypeNode(node);
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
@ -5910,8 +5910,8 @@ namespace ts {
|
||||
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node, aliasSymbol, aliasTypeArguments);
|
||||
case SyntaxKind.TypeOperator:
|
||||
return getTypeFromTypeOperatorNode(<TypeOperatorNode>node);
|
||||
case SyntaxKind.PropertyAccessType:
|
||||
return getTypeFromPropertyAccessTypeNode(<PropertyAccessTypeNode>node);
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
return getTypeFromIndexedAccessTypeNode(<IndexedAccessTypeNode>node);
|
||||
// This function assumes that an identifier or qualified name is a type expression
|
||||
// Callers should first ensure this by calling isTypeNode
|
||||
case SyntaxKind.Identifier:
|
||||
@ -6173,11 +6173,11 @@ namespace ts {
|
||||
if (type.flags & TypeFlags.Intersection) {
|
||||
return getIntersectionType(instantiateList((<IntersectionType>type).types, mapper, instantiateType), type.aliasSymbol, mapper.targetTypes);
|
||||
}
|
||||
if (type.flags & TypeFlags.PropertyName) {
|
||||
return getPropertyNameType(instantiateType((<PropertyNameType>type).type, mapper));
|
||||
if (type.flags & TypeFlags.Index) {
|
||||
return getIndexType(instantiateType((<IndexType>type).type, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.PropertyAccess) {
|
||||
return getPropertyAccessType(instantiateType((<PropertyAccessType>type).objectType, mapper), instantiateType((<PropertyAccessType>type).keyType, mapper));
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
|
||||
}
|
||||
}
|
||||
return type;
|
||||
@ -8114,7 +8114,7 @@ namespace ts {
|
||||
|
||||
function hasPrimitiveConstraint(type: TypeParameter): boolean {
|
||||
const constraint = getConstraintOfTypeParameter(type);
|
||||
return constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.PropertyName);
|
||||
return constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.Index);
|
||||
}
|
||||
|
||||
function getInferredType(context: InferenceContext, index: number): Type {
|
||||
@ -11520,14 +11520,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain base constraint such that we can bail out if the constraint is an unknown type
|
||||
const objectType = getApparentType(checkNonNullExpression(node.expression));
|
||||
let objectType = checkNonNullExpression(node.expression);
|
||||
const indexType = node.argumentExpression ? checkExpression(node.argumentExpression) : unknownType;
|
||||
|
||||
if (objectType === unknownType || objectType === silentNeverType) {
|
||||
return objectType;
|
||||
}
|
||||
|
||||
if (indexType.flags & TypeFlags.TypeParameter &&
|
||||
isTypeAssignableTo(getConstraintOfTypeParameter(<TypeParameter>indexType), getIndexType(objectType))) {
|
||||
return getIndexedAccessType(objectType, indexType);
|
||||
}
|
||||
|
||||
objectType = getApparentType(objectType);
|
||||
|
||||
const isConstEnum = isConstEnumObjectType(objectType);
|
||||
if (isConstEnum &&
|
||||
(!node.argumentExpression || node.argumentExpression.kind !== SyntaxKind.StringLiteral)) {
|
||||
@ -15043,6 +15049,10 @@ namespace ts {
|
||||
forEach(node.types, checkSourceElement);
|
||||
}
|
||||
|
||||
function checkIndexedAccessType(node: IndexedAccessTypeNode) {
|
||||
getTypeFromIndexedAccessTypeNode(node);
|
||||
}
|
||||
|
||||
function isPrivateWithinAmbient(node: Node): boolean {
|
||||
return (getModifierFlags(node) & ModifierFlags.Private) && isInAmbientContext(node);
|
||||
}
|
||||
@ -18327,6 +18337,8 @@ namespace ts {
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.TypeOperator:
|
||||
return checkSourceElement((<ParenthesizedTypeNode | TypeOperatorNode>node).type);
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
return checkIndexedAccessType(<IndexedAccessTypeNode>node);
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return checkFunctionDeclaration(<FunctionDeclaration>node);
|
||||
case SyntaxKind.Block:
|
||||
|
||||
@ -415,8 +415,8 @@ namespace ts {
|
||||
return emitParenType(<ParenthesizedTypeNode>type);
|
||||
case SyntaxKind.TypeOperator:
|
||||
return emitTypeOperator(<TypeOperatorNode>type);
|
||||
case SyntaxKind.PropertyAccessType:
|
||||
return emitPropertyAccessType(<PropertyAccessTypeNode>type);
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
return emitPropertyAccessType(<IndexedAccessTypeNode>type);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
return emitSignatureDeclarationWithJsDocComments(<FunctionOrConstructorTypeNode>type);
|
||||
@ -516,10 +516,10 @@ namespace ts {
|
||||
emitType(type.type);
|
||||
}
|
||||
|
||||
function emitPropertyAccessType(node: PropertyAccessTypeNode) {
|
||||
function emitPropertyAccessType(node: IndexedAccessTypeNode) {
|
||||
emitType(node.objectType);
|
||||
write("[");
|
||||
emitType(node.keyType);
|
||||
emitType(node.indexType);
|
||||
write("]");
|
||||
}
|
||||
|
||||
|
||||
@ -596,8 +596,8 @@ const _super = (function (geti, seti) {
|
||||
return emitThisType();
|
||||
case SyntaxKind.TypeOperator:
|
||||
return emitTypeOperator(<TypeOperatorNode>node);
|
||||
case SyntaxKind.PropertyAccessType:
|
||||
return emitPropertyAccessType(<PropertyAccessTypeNode>node);
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
return emitPropertyAccessType(<IndexedAccessTypeNode>node);
|
||||
case SyntaxKind.LiteralType:
|
||||
return emitLiteralType(<LiteralTypeNode>node);
|
||||
|
||||
@ -1098,10 +1098,10 @@ const _super = (function (geti, seti) {
|
||||
emit(node.type);
|
||||
}
|
||||
|
||||
function emitPropertyAccessType(node: PropertyAccessTypeNode) {
|
||||
function emitPropertyAccessType(node: IndexedAccessTypeNode) {
|
||||
emit(node.objectType);
|
||||
write("[");
|
||||
emit(node.keyType);
|
||||
emit(node.indexType);
|
||||
write("]");
|
||||
}
|
||||
|
||||
|
||||
@ -136,9 +136,9 @@ namespace ts {
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.TypeOperator:
|
||||
return visitNode(cbNode, (<ParenthesizedTypeNode | TypeOperatorNode>node).type);
|
||||
case SyntaxKind.PropertyAccessType:
|
||||
return visitNode(cbNode, (<PropertyAccessTypeNode>node).objectType) ||
|
||||
visitNode(cbNode, (<PropertyAccessTypeNode>node).keyType);
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
return visitNode(cbNode, (<IndexedAccessTypeNode>node).objectType) ||
|
||||
visitNode(cbNode, (<IndexedAccessTypeNode>node).indexType);
|
||||
case SyntaxKind.LiteralType:
|
||||
return visitNode(cbNode, (<LiteralTypeNode>node).literal);
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
@ -2523,9 +2523,9 @@ namespace ts {
|
||||
let type = parseNonArrayType();
|
||||
while (!scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.OpenBracketToken)) {
|
||||
if (isStartOfType()) {
|
||||
const node = <PropertyAccessTypeNode>createNode(SyntaxKind.PropertyAccessType, type.pos);
|
||||
const node = <IndexedAccessTypeNode>createNode(SyntaxKind.IndexedAccessType, type.pos);
|
||||
node.objectType = type;
|
||||
node.keyType = parseType();
|
||||
node.indexType = parseType();
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
type = finishNode(node);
|
||||
}
|
||||
|
||||
@ -289,7 +289,7 @@ namespace ts {
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.ThisType:
|
||||
case SyntaxKind.TypeOperator:
|
||||
case SyntaxKind.PropertyAccessType:
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
case SyntaxKind.LiteralType:
|
||||
// TypeScript type nodes are elided.
|
||||
|
||||
@ -1859,7 +1859,7 @@ namespace ts {
|
||||
// Fallthrough
|
||||
case SyntaxKind.TypeQuery:
|
||||
case SyntaxKind.TypeOperator:
|
||||
case SyntaxKind.PropertyAccessType:
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.ThisType:
|
||||
|
||||
@ -218,7 +218,7 @@ namespace ts {
|
||||
ParenthesizedType,
|
||||
ThisType,
|
||||
TypeOperator,
|
||||
PropertyAccessType,
|
||||
IndexedAccessType,
|
||||
LiteralType,
|
||||
// Binding patterns
|
||||
ObjectBindingPattern,
|
||||
@ -879,10 +879,10 @@ namespace ts {
|
||||
type: TypeNode;
|
||||
}
|
||||
|
||||
export interface PropertyAccessTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.PropertyAccessType;
|
||||
export interface IndexedAccessTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.IndexedAccessType;
|
||||
objectType: TypeNode;
|
||||
keyType: TypeNode;
|
||||
indexType: TypeNode;
|
||||
}
|
||||
|
||||
export interface LiteralTypeNode extends TypeNode {
|
||||
@ -2630,8 +2630,8 @@ namespace ts {
|
||||
Object = 1 << 15, // Object type
|
||||
Union = 1 << 16, // Union (T | U)
|
||||
Intersection = 1 << 17, // Intersection (T & U)
|
||||
PropertyName = 1 << 18, // keyof T
|
||||
PropertyAccess = 1 << 19, // T[K]
|
||||
Index = 1 << 18, // keyof T
|
||||
IndexedAccess = 1 << 19, // T[K]
|
||||
/* @internal */
|
||||
FreshLiteral = 1 << 20, // Fresh literal type
|
||||
/* @internal */
|
||||
@ -2652,7 +2652,7 @@ namespace ts {
|
||||
Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never,
|
||||
/* @internal */
|
||||
Primitive = String | Number | Boolean | Enum | ESSymbol | Void | Undefined | Null | Literal,
|
||||
StringLike = String | StringLiteral | PropertyName,
|
||||
StringLike = String | StringLiteral | Index,
|
||||
NumberLike = Number | NumberLiteral | Enum | EnumLiteral,
|
||||
BooleanLike = Boolean | BooleanLiteral,
|
||||
EnumLike = Enum | EnumLiteral,
|
||||
@ -2662,7 +2662,7 @@ namespace ts {
|
||||
|
||||
// 'Narrowable' types are types where narrowing actually narrows.
|
||||
// This *should* be every type other than null, undefined, void, and never
|
||||
Narrowable = Any | StructuredType | TypeParameter | PropertyAccess | StringLike | NumberLike | BooleanLike | ESSymbol,
|
||||
Narrowable = Any | StructuredType | TypeParameter | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol,
|
||||
NotUnionOrUnit = Any | ESSymbol | Object,
|
||||
/* @internal */
|
||||
RequiresWidening = ContainsWideningType | ContainsObjectLiteral,
|
||||
@ -2825,20 +2825,20 @@ namespace ts {
|
||||
/* @internal */
|
||||
resolvedApparentType: Type;
|
||||
/* @internal */
|
||||
resolvedPropertyNameType: PropertyNameType;
|
||||
resolvedIndexType: IndexType;
|
||||
/* @internal */
|
||||
resolvedPropertyAccessTypes: PropertyAccessType[];
|
||||
resolvedIndexedAccessTypes: IndexedAccessType[];
|
||||
/* @internal */
|
||||
isThisType?: boolean;
|
||||
}
|
||||
|
||||
export interface PropertyNameType extends Type {
|
||||
export interface IndexType extends Type {
|
||||
type: TypeParameter;
|
||||
}
|
||||
|
||||
export interface PropertyAccessType extends Type {
|
||||
export interface IndexedAccessType extends Type {
|
||||
objectType: Type;
|
||||
keyType: TypeParameter;
|
||||
indexType: TypeParameter;
|
||||
}
|
||||
|
||||
export const enum SignatureKind {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user