mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-17 10:40:34 -05:00
Merge pull request #22707 from Microsoft/fixIndexedAccessInConditionalType
Fix indexed access in conditional type
This commit is contained in:
@@ -3040,7 +3040,7 @@ namespace ts {
|
||||
return createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode);
|
||||
}
|
||||
if (type.flags & TypeFlags.Substitution) {
|
||||
return typeToTypeNodeHelper((<SubstitutionType>type).typeParameter, context);
|
||||
return typeToTypeNodeHelper((<SubstitutionType>type).typeVariable, context);
|
||||
}
|
||||
|
||||
Debug.fail("Should be unreachable.");
|
||||
@@ -7305,7 +7305,7 @@ namespace ts {
|
||||
const res = tryGetDeclaredTypeOfSymbol(symbol);
|
||||
if (res) {
|
||||
return checkNoTypeArguments(node, symbol) ?
|
||||
res.flags & TypeFlags.TypeParameter ? getConstrainedTypeParameter(<TypeParameter>res, node) : res :
|
||||
res.flags & TypeFlags.TypeParameter ? getConstrainedTypeVariable(<TypeParameter>res, node) : res :
|
||||
unknownType;
|
||||
}
|
||||
|
||||
@@ -7344,25 +7344,36 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getSubstitutionType(typeParameter: TypeParameter, substitute: Type) {
|
||||
function getSubstitutionType(typeVariable: TypeVariable, substitute: Type) {
|
||||
const result = <SubstitutionType>createType(TypeFlags.Substitution);
|
||||
result.typeParameter = typeParameter;
|
||||
result.typeVariable = typeVariable;
|
||||
result.substitute = substitute;
|
||||
return result;
|
||||
}
|
||||
|
||||
function getConstrainedTypeParameter(typeParameter: TypeParameter, node: Node) {
|
||||
function isUnaryTupleTypeNode(node: TypeNode) {
|
||||
return node.kind === SyntaxKind.TupleType && (<TupleTypeNode>node).elementTypes.length === 1;
|
||||
}
|
||||
|
||||
function getImpliedConstraint(typeVariable: TypeVariable, checkNode: TypeNode, extendsNode: TypeNode): Type {
|
||||
return isUnaryTupleTypeNode(checkNode) && isUnaryTupleTypeNode(extendsNode) ? getImpliedConstraint(typeVariable, (<TupleTypeNode>checkNode).elementTypes[0], (<TupleTypeNode>extendsNode).elementTypes[0]) :
|
||||
getActualTypeVariable(getTypeFromTypeNode(checkNode)) === typeVariable ? getTypeFromTypeNode(extendsNode) :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function getConstrainedTypeVariable(typeVariable: TypeVariable, node: Node) {
|
||||
let constraints: Type[];
|
||||
while (isPartOfTypeNode(node)) {
|
||||
const parent = node.parent;
|
||||
if (parent.kind === SyntaxKind.ConditionalType && node === (<ConditionalTypeNode>parent).trueType) {
|
||||
if (getTypeFromTypeNode((<ConditionalTypeNode>parent).checkType) === typeParameter) {
|
||||
constraints = append(constraints, getTypeFromTypeNode((<ConditionalTypeNode>parent).extendsType));
|
||||
const constraint = getImpliedConstraint(typeVariable, (<ConditionalTypeNode>parent).checkType, (<ConditionalTypeNode>parent).extendsType);
|
||||
if (constraint) {
|
||||
constraints = append(constraints, constraint);
|
||||
}
|
||||
}
|
||||
node = parent;
|
||||
}
|
||||
return constraints ? getSubstitutionType(typeParameter, getIntersectionType(append(constraints, typeParameter))) : typeParameter;
|
||||
return constraints ? getSubstitutionType(typeVariable, getIntersectionType(append(constraints, typeVariable))) : typeVariable;
|
||||
}
|
||||
|
||||
function isJSDocTypeReference(node: TypeReferenceType): node is TypeReferenceNode {
|
||||
@@ -8258,7 +8269,13 @@ namespace ts {
|
||||
function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = getIndexedAccessType(getTypeFromTypeNode(node.objectType), getTypeFromTypeNode(node.indexType), node);
|
||||
const objectType = getTypeFromTypeNode(node.objectType);
|
||||
const indexType = getTypeFromTypeNode(node.indexType);
|
||||
const resolved = getIndexedAccessType(objectType, indexType, node);
|
||||
links.resolvedType = resolved.flags & TypeFlags.IndexedAccess &&
|
||||
(<IndexedAccessType>resolved).objectType === objectType &&
|
||||
(<IndexedAccessType>resolved).indexType === indexType ?
|
||||
getConstrainedTypeVariable(<IndexedAccessType>resolved, node) : resolved;
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
@@ -8278,8 +8295,8 @@ namespace ts {
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getActualTypeParameter(type: Type) {
|
||||
return type.flags & TypeFlags.Substitution ? (<SubstitutionType>type).typeParameter : type;
|
||||
function getActualTypeVariable(type: Type) {
|
||||
return type.flags & TypeFlags.Substitution ? (<SubstitutionType>type).typeVariable : type;
|
||||
}
|
||||
|
||||
function getConditionalType(root: ConditionalRoot, mapper: TypeMapper): Type {
|
||||
@@ -8323,7 +8340,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
// Return a deferred type for a check that is neither definitely true nor definitely false
|
||||
const erasedCheckType = getActualTypeParameter(checkType);
|
||||
const erasedCheckType = getActualTypeVariable(checkType);
|
||||
const result = <ConditionalType>createType(TypeFlags.Conditional);
|
||||
result.root = root;
|
||||
result.checkType = erasedCheckType;
|
||||
@@ -9043,7 +9060,7 @@ namespace ts {
|
||||
return getConditionalTypeInstantiation(<ConditionalType>type, combineTypeMappers((<ConditionalType>type).mapper, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.Substitution) {
|
||||
return mapper((<SubstitutionType>type).typeParameter);
|
||||
return instantiateType((<SubstitutionType>type).typeVariable, mapper);
|
||||
}
|
||||
}
|
||||
return type;
|
||||
@@ -9650,10 +9667,10 @@ namespace ts {
|
||||
target = (<LiteralType>target).regularType;
|
||||
}
|
||||
if (source.flags & TypeFlags.Substitution) {
|
||||
source = relation === definitelyAssignableRelation ? (<SubstitutionType>source).typeParameter : (<SubstitutionType>source).substitute;
|
||||
source = relation === definitelyAssignableRelation ? (<SubstitutionType>source).typeVariable : (<SubstitutionType>source).substitute;
|
||||
}
|
||||
if (target.flags & TypeFlags.Substitution) {
|
||||
target = (<SubstitutionType>target).typeParameter;
|
||||
target = (<SubstitutionType>target).typeVariable;
|
||||
}
|
||||
|
||||
// both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases
|
||||
|
||||
@@ -3845,6 +3845,8 @@ namespace ts {
|
||||
constraint?: Type;
|
||||
}
|
||||
|
||||
export type TypeVariable = TypeParameter | IndexedAccessType;
|
||||
|
||||
// keyof T types (TypeFlags.Index)
|
||||
export interface IndexType extends InstantiableType {
|
||||
type: InstantiableType | UnionOrIntersectionType;
|
||||
@@ -3876,14 +3878,14 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Type parameter substitution (TypeFlags.Substitution)
|
||||
// Substitution types are created for type parameter references that occur in the true branch
|
||||
// of a conditional type. For example, in 'T extends string ? Foo<T> : Bar<T>', the reference to
|
||||
// T in Foo<T> is resolved as a substitution type that substitutes 'string & T' for T. Thus, if
|
||||
// Foo has a 'string' constraint on its type parameter, T will satisfy it. Substitution types
|
||||
// disappear upon instantiation (just like type parameters).
|
||||
// Substitution types are created for type parameters or indexed access types that occur in the
|
||||
// true branch of a conditional type. For example, in 'T extends string ? Foo<T> : Bar<T>', the
|
||||
// reference to T in Foo<T> is resolved as a substitution type that substitutes 'string & T' for T.
|
||||
// Thus, if Foo has a 'string' constraint on its type parameter, T will satisfy it. Substitution
|
||||
// types disappear upon instantiation (just like type parameters).
|
||||
export interface SubstitutionType extends InstantiableType {
|
||||
typeParameter: TypeParameter; // Target type parameter
|
||||
substitute: Type; // Type to substitute for type parameter
|
||||
typeVariable: TypeVariable; // Target type variable
|
||||
substitute: Type; // Type to substitute for type parameter
|
||||
}
|
||||
|
||||
export const enum SignatureKind {
|
||||
|
||||
Reference in New Issue
Block a user