mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Implement type inference in conditional types
This commit is contained in:
+32
-1
@@ -101,6 +101,7 @@ namespace ts {
|
||||
HasLocals = 1 << 5,
|
||||
IsInterface = 1 << 6,
|
||||
IsObjectLiteralOrClassExpressionMethod = 1 << 7,
|
||||
IsInferenceContainer = 1 << 8,
|
||||
}
|
||||
|
||||
const binder = createBinder();
|
||||
@@ -119,6 +120,7 @@ namespace ts {
|
||||
let parent: Node;
|
||||
let container: Node;
|
||||
let blockScopeContainer: Node;
|
||||
let inferenceContainer: Node;
|
||||
let lastContainer: Node;
|
||||
let seenThisKeyword: boolean;
|
||||
|
||||
@@ -186,6 +188,7 @@ namespace ts {
|
||||
parent = undefined;
|
||||
container = undefined;
|
||||
blockScopeContainer = undefined;
|
||||
inferenceContainer = undefined;
|
||||
lastContainer = undefined;
|
||||
seenThisKeyword = false;
|
||||
currentFlow = undefined;
|
||||
@@ -561,6 +564,13 @@ namespace ts {
|
||||
bindChildren(node);
|
||||
node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis : node.flags & ~NodeFlags.ContainsThis;
|
||||
}
|
||||
else if (containerFlags & ContainerFlags.IsInferenceContainer) {
|
||||
const saveInferenceContainer = inferenceContainer;
|
||||
inferenceContainer = node;
|
||||
node.locals = undefined;
|
||||
bindChildren(node);
|
||||
inferenceContainer = saveInferenceContainer;
|
||||
}
|
||||
else {
|
||||
bindChildren(node);
|
||||
}
|
||||
@@ -1417,6 +1427,9 @@ namespace ts {
|
||||
case SyntaxKind.MappedType:
|
||||
return ContainerFlags.IsContainer | ContainerFlags.HasLocals;
|
||||
|
||||
case SyntaxKind.ConditionalType:
|
||||
return ContainerFlags.IsInferenceContainer;
|
||||
|
||||
case SyntaxKind.SourceFile:
|
||||
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals;
|
||||
|
||||
@@ -2059,7 +2072,7 @@ namespace ts {
|
||||
case SyntaxKind.TypePredicate:
|
||||
return checkTypePredicate(node as TypePredicateNode);
|
||||
case SyntaxKind.TypeParameter:
|
||||
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
|
||||
return bindTypeParameter(node as TypeParameterDeclaration);
|
||||
case SyntaxKind.Parameter:
|
||||
return bindParameter(<ParameterDeclaration>node);
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
@@ -2576,6 +2589,23 @@ namespace ts {
|
||||
: declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
|
||||
}
|
||||
|
||||
function bindTypeParameter(node: TypeParameterDeclaration) {
|
||||
if (node.parent.kind === SyntaxKind.InferType) {
|
||||
if (inferenceContainer) {
|
||||
if (!inferenceContainer.locals) {
|
||||
inferenceContainer.locals = createSymbolTable();
|
||||
}
|
||||
declareSymbol(inferenceContainer.locals, /*parent*/ undefined, node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
|
||||
}
|
||||
else {
|
||||
bindAnonymousDeclaration(node, SymbolFlags.TypeParameter, getDeclarationName(node));
|
||||
}
|
||||
}
|
||||
else {
|
||||
declareSymbolAndAddToSymbolTable(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
|
||||
}
|
||||
}
|
||||
|
||||
// reachability checks
|
||||
|
||||
function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean {
|
||||
@@ -3441,6 +3471,7 @@ namespace ts {
|
||||
case SyntaxKind.UnionType:
|
||||
case SyntaxKind.IntersectionType:
|
||||
case SyntaxKind.ConditionalType:
|
||||
case SyntaxKind.InferType:
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
|
||||
+66
-11
@@ -1169,6 +1169,11 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (location.kind === SyntaxKind.ConditionalType) {
|
||||
// A type parameter declared using 'infer T' in a conditional type is visible only in
|
||||
// the true branch of the conditional type.
|
||||
useResult = lastLocation === (<ConditionalTypeNode>location).trueType;
|
||||
}
|
||||
|
||||
if (useResult) {
|
||||
break loop;
|
||||
@@ -4628,10 +4633,14 @@ namespace ts {
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.JSDocTemplateTag:
|
||||
case SyntaxKind.MappedType:
|
||||
case SyntaxKind.ConditionalType:
|
||||
const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes);
|
||||
if (node.kind === SyntaxKind.MappedType) {
|
||||
return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode((<MappedTypeNode>node).typeParameter)));
|
||||
}
|
||||
else if (node.kind === SyntaxKind.ConditionalType) {
|
||||
return concatenate(outerTypeParameters, getInferTypeParameters(<ConditionalTypeNode>node));
|
||||
}
|
||||
const outerAndOwnTypeParameters = appendTypeParameters(outerTypeParameters, getEffectiveTypeParameterDeclarations(<DeclarationWithTypeParameters>node) || emptyArray);
|
||||
const thisType = includeThisTypes &&
|
||||
(node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.InterfaceDeclaration) &&
|
||||
@@ -8078,12 +8087,13 @@ namespace ts {
|
||||
return type.flags & TypeFlags.Substitution ? (<SubstitutionType>type).typeParameter : type;
|
||||
}
|
||||
|
||||
function createConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, target: ConditionalType, mapper: TypeMapper, aliasSymbol: Symbol, aliasTypeArguments: Type[]) {
|
||||
function createConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, inferTypeParameters: TypeParameter[], target: ConditionalType, mapper: TypeMapper, aliasSymbol: Symbol, aliasTypeArguments: Type[]) {
|
||||
const type = <ConditionalType>createType(TypeFlags.Conditional);
|
||||
type.checkType = checkType;
|
||||
type.extendsType = extendsType;
|
||||
type.trueType = trueType;
|
||||
type.falseType = falseType;
|
||||
type.inferTypeParameters = inferTypeParameters;
|
||||
type.target = target;
|
||||
type.mapper = mapper;
|
||||
type.aliasSymbol = aliasSymbol;
|
||||
@@ -8091,14 +8101,29 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
function getConditionalType(checkType: Type, extendsType: Type, baseTrueType: Type, baseFalseType: Type, target: ConditionalType, mapper: TypeMapper, aliasSymbol?: Symbol, baseAliasTypeArguments?: Type[]): Type {
|
||||
function getConditionalType(checkType: Type, baseExtendsType: Type, baseTrueType: Type, baseFalseType: Type, inferTypeParameters: TypeParameter[], target: ConditionalType, mapper: TypeMapper, aliasSymbol?: Symbol, baseAliasTypeArguments?: Type[]): Type {
|
||||
// Instantiate extends type without instantiating any 'infer T' type parameters
|
||||
const extendsType = instantiateType(baseExtendsType, mapper);
|
||||
let combinedMapper: TypeMapper;
|
||||
if (inferTypeParameters) {
|
||||
const inferences = map(inferTypeParameters, createInferenceInfo);
|
||||
// We don't want inferences from constraints as they may cause us to eagerly resolve the
|
||||
// conditional type instead of deferring resolution.
|
||||
inferTypes(inferences, checkType, extendsType, InferencePriority.NoConstraints);
|
||||
// We infer 'never' when there are no candidates for a type parameter
|
||||
const inferredTypes = map(inferences, inference => getTypeFromInference(inference) || neverType);
|
||||
const inferenceMapper = createTypeMapper(inferTypeParameters, inferredTypes);
|
||||
combinedMapper = mapper ? combineTypeMappers(mapper, inferenceMapper) : inferenceMapper;
|
||||
}
|
||||
// Return union of trueType and falseType for any and never since they match anything
|
||||
if (checkType.flags & (TypeFlags.Any | TypeFlags.Never)) {
|
||||
return getUnionType([instantiateType(baseTrueType, mapper), instantiateType(baseFalseType, mapper)]);
|
||||
return getUnionType([instantiateType(baseTrueType, combinedMapper || mapper), instantiateType(baseFalseType, mapper)]);
|
||||
}
|
||||
// Instantiate the extends type including inferences for 'infer T' type parameters
|
||||
const inferredExtendsType = combinedMapper ? instantiateType(baseExtendsType, combinedMapper) : extendsType;
|
||||
// Return trueType for a definitely true extends check
|
||||
if (isTypeAssignableTo(checkType, extendsType)) {
|
||||
return instantiateType(baseTrueType, mapper);
|
||||
if (isTypeAssignableTo(checkType, inferredExtendsType)) {
|
||||
return instantiateType(baseTrueType, combinedMapper || mapper);
|
||||
}
|
||||
// Return falseType for a definitely false extends check
|
||||
if (!isTypeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) {
|
||||
@@ -8114,25 +8139,45 @@ namespace ts {
|
||||
return cached;
|
||||
}
|
||||
const result = createConditionalType(erasedCheckType, extendsType, trueType, falseType,
|
||||
target, mapper, aliasSymbol, instantiateTypes(baseAliasTypeArguments, mapper));
|
||||
inferTypeParameters, target, mapper, aliasSymbol, instantiateTypes(baseAliasTypeArguments, mapper));
|
||||
if (id) {
|
||||
conditionalTypes.set(id, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getInferTypeParameters(node: ConditionalTypeNode): TypeParameter[] {
|
||||
let result: TypeParameter[];
|
||||
if (node.locals) {
|
||||
node.locals.forEach(symbol => {
|
||||
if (symbol.flags & SymbolFlags.TypeParameter) {
|
||||
result = append(result, getDeclaredTypeOfSymbol(symbol));
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = getConditionalType(
|
||||
getTypeFromTypeNode(node.checkType), getTypeFromTypeNode(node.extendsType),
|
||||
getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType),
|
||||
/*target*/ undefined, /*mapper*/ undefined,
|
||||
getInferTypeParameters(node), /*target*/ undefined, /*mapper*/ undefined,
|
||||
getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getTypeFromInferTypeNode(node: InferTypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node.typeParameter));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: TypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
@@ -8423,6 +8468,8 @@ namespace ts {
|
||||
return getTypeFromMappedTypeNode(<MappedTypeNode>node);
|
||||
case SyntaxKind.ConditionalType:
|
||||
return getTypeFromConditionalTypeNode(<ConditionalTypeNode>node);
|
||||
case SyntaxKind.InferType:
|
||||
return getTypeFromInferTypeNode(<InferTypeNode>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:
|
||||
@@ -8714,8 +8761,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function instantiateConditionalType(type: ConditionalType, mapper: TypeMapper): Type {
|
||||
return getConditionalType(instantiateType(type.checkType, mapper), instantiateType(type.extendsType, mapper),
|
||||
type.trueType, type.falseType, type, mapper, type.aliasSymbol, type.aliasTypeArguments);
|
||||
return getConditionalType(instantiateType(type.checkType, mapper), type.extendsType, type.trueType, type.falseType,
|
||||
type.inferTypeParameters, type, mapper, type.aliasSymbol, type.aliasTypeArguments);
|
||||
}
|
||||
|
||||
function instantiateType(type: Type, mapper: TypeMapper): Type {
|
||||
@@ -11206,7 +11253,7 @@ namespace ts {
|
||||
const templateType = getTemplateTypeFromMappedType(target);
|
||||
const inference = createInferenceInfo(typeParameter);
|
||||
inferTypes([inference], sourceType, templateType);
|
||||
return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) : emptyObjectType;
|
||||
return getTypeFromInference(inference) || emptyObjectType;
|
||||
}
|
||||
|
||||
function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean) {
|
||||
@@ -11222,6 +11269,12 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getTypeFromInference(inference: InferenceInfo) {
|
||||
return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) :
|
||||
inference.contraCandidates ? getCommonSubtype(inference.contraCandidates) :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) {
|
||||
let symbolStack: Symbol[];
|
||||
let visited: Map<boolean>;
|
||||
@@ -11381,7 +11434,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
source = getApparentType(source);
|
||||
if (!(priority && InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) {
|
||||
source = getApparentType(source);
|
||||
}
|
||||
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
|
||||
const key = source.id + "," + target.id;
|
||||
if (visited && visited.get(key)) {
|
||||
|
||||
@@ -452,6 +452,8 @@ namespace ts {
|
||||
return emitIntersectionType(<IntersectionTypeNode>type);
|
||||
case SyntaxKind.ConditionalType:
|
||||
return emitConditionalType(<ConditionalTypeNode>type);
|
||||
case SyntaxKind.InferType:
|
||||
return emitInferType(<InferTypeNode>type);
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
return emitParenType(<ParenthesizedTypeNode>type);
|
||||
case SyntaxKind.TypeOperator:
|
||||
@@ -557,6 +559,11 @@ namespace ts {
|
||||
emitType(node.falseType);
|
||||
}
|
||||
|
||||
function emitInferType(node: InferTypeNode) {
|
||||
write("infer ");
|
||||
writeTextOfNode(currentText, node.typeParameter.name);
|
||||
}
|
||||
|
||||
function emitParenType(type: ParenthesizedTypeNode) {
|
||||
write("(");
|
||||
emitType(type.type);
|
||||
|
||||
@@ -602,6 +602,8 @@ namespace ts {
|
||||
return emitIntersectionType(<IntersectionTypeNode>node);
|
||||
case SyntaxKind.ConditionalType:
|
||||
return emitConditionalType(<ConditionalTypeNode>node);
|
||||
case SyntaxKind.InferType:
|
||||
return emitInferType(<InferTypeNode>node);
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
return emitParenthesizedType(<ParenthesizedTypeNode>node);
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
@@ -1202,6 +1204,11 @@ namespace ts {
|
||||
emit(node.falseType);
|
||||
}
|
||||
|
||||
function emitInferType(node: InferTypeNode) {
|
||||
write("infer ");
|
||||
emit(node.typeParameter);
|
||||
}
|
||||
|
||||
function emitParenthesizedType(node: ParenthesizedTypeNode) {
|
||||
writePunctuation("(");
|
||||
emit(node.type);
|
||||
|
||||
@@ -747,6 +747,18 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createInferTypeNode(typeParameter: TypeParameterDeclaration) {
|
||||
const node = <InferTypeNode>createSynthesizedNode(SyntaxKind.InferType);
|
||||
node.typeParameter = typeParameter;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateInferTypeNode(node: InferTypeNode, typeParameter: TypeParameterDeclaration) {
|
||||
return node.typeParameter !== typeParameter
|
||||
? updateNode(createInferTypeNode(typeParameter), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createParenthesizedType(type: TypeNode) {
|
||||
const node = <ParenthesizedTypeNode>createSynthesizedNode(SyntaxKind.ParenthesizedType);
|
||||
node.type = type;
|
||||
|
||||
@@ -180,6 +180,8 @@ namespace ts {
|
||||
visitNode(cbNode, (<ConditionalTypeNode>node).extendsType) ||
|
||||
visitNode(cbNode, (<ConditionalTypeNode>node).trueType) ||
|
||||
visitNode(cbNode, (<ConditionalTypeNode>node).falseType);
|
||||
case SyntaxKind.InferType:
|
||||
return visitNode(cbNode, (<InferTypeNode>node).typeParameter);
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.TypeOperator:
|
||||
return visitNode(cbNode, (<ParenthesizedTypeNode | TypeOperatorNode>node).type);
|
||||
@@ -2647,6 +2649,15 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseInferType(): InferTypeNode {
|
||||
const node = <InferTypeNode>createNode(SyntaxKind.InferType);
|
||||
parseExpected(SyntaxKind.InferKeyword);
|
||||
const typeParameter = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter);
|
||||
typeParameter.name = parseIdentifier();
|
||||
node.typeParameter = finishNode(typeParameter);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseFunctionOrConstructorType(kind: SyntaxKind): FunctionOrConstructorTypeNode {
|
||||
const node = <FunctionOrConstructorTypeNode>createNodeWithJSDoc(kind);
|
||||
if (kind === SyntaxKind.ConstructorType) {
|
||||
@@ -2733,6 +2744,8 @@ namespace ts {
|
||||
return parseTupleType();
|
||||
case SyntaxKind.OpenParenToken:
|
||||
return parseParenthesizedType();
|
||||
case SyntaxKind.InferKeyword:
|
||||
return parseInferType();
|
||||
default:
|
||||
return parseTypeReference();
|
||||
}
|
||||
@@ -2767,6 +2780,7 @@ namespace ts {
|
||||
case SyntaxKind.QuestionToken:
|
||||
case SyntaxKind.ExclamationToken:
|
||||
case SyntaxKind.DotDotDotToken:
|
||||
case SyntaxKind.InferKeyword:
|
||||
return true;
|
||||
case SyntaxKind.MinusToken:
|
||||
return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral);
|
||||
|
||||
@@ -92,6 +92,7 @@ namespace ts {
|
||||
"implements": SyntaxKind.ImplementsKeyword,
|
||||
"import": SyntaxKind.ImportKeyword,
|
||||
"in": SyntaxKind.InKeyword,
|
||||
"infer": SyntaxKind.InferKeyword,
|
||||
"instanceof": SyntaxKind.InstanceOfKeyword,
|
||||
"interface": SyntaxKind.InterfaceKeyword,
|
||||
"is": SyntaxKind.IsKeyword,
|
||||
|
||||
+11
-1
@@ -215,6 +215,7 @@ namespace ts {
|
||||
ConstructorKeyword,
|
||||
DeclareKeyword,
|
||||
GetKeyword,
|
||||
InferKeyword,
|
||||
IsKeyword,
|
||||
KeyOfKeyword,
|
||||
ModuleKeyword,
|
||||
@@ -266,6 +267,7 @@ namespace ts {
|
||||
UnionType,
|
||||
IntersectionType,
|
||||
ConditionalType,
|
||||
InferType,
|
||||
ParenthesizedType,
|
||||
ThisType,
|
||||
TypeOperator,
|
||||
@@ -771,7 +773,7 @@ namespace ts {
|
||||
|
||||
export interface TypeParameterDeclaration extends NamedDeclaration {
|
||||
kind: SyntaxKind.TypeParameter;
|
||||
parent?: DeclarationWithTypeParameters;
|
||||
parent?: DeclarationWithTypeParameters | InferTypeNode;
|
||||
name: Identifier;
|
||||
constraint?: TypeNode;
|
||||
default?: TypeNode;
|
||||
@@ -1125,6 +1127,11 @@ namespace ts {
|
||||
falseType: TypeNode;
|
||||
}
|
||||
|
||||
export interface InferTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.InferType;
|
||||
typeParameter: TypeParameterDeclaration;
|
||||
}
|
||||
|
||||
export interface ParenthesizedTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.ParenthesizedType;
|
||||
type: TypeNode;
|
||||
@@ -3795,6 +3802,8 @@ namespace ts {
|
||||
trueType: Type;
|
||||
falseType: Type;
|
||||
/* @internal */
|
||||
inferTypeParameters: TypeParameter[];
|
||||
/* @internal */
|
||||
target?: ConditionalType;
|
||||
/* @internal */
|
||||
mapper?: TypeMapper;
|
||||
@@ -3870,6 +3879,7 @@ namespace ts {
|
||||
NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type
|
||||
MappedType = 1 << 1, // Reverse inference for mapped type
|
||||
ReturnType = 1 << 2, // Inference made from return type of generic function
|
||||
NoConstraints = 1 << 3, // Don't infer from constraints of instantiable types
|
||||
}
|
||||
|
||||
export interface InferenceInfo {
|
||||
|
||||
@@ -4559,6 +4559,10 @@ namespace ts {
|
||||
return node.kind === SyntaxKind.ConditionalType;
|
||||
}
|
||||
|
||||
export function isInferTypeNode(node: Node): node is InferTypeNode {
|
||||
return node.kind === SyntaxKind.InferType;
|
||||
}
|
||||
|
||||
export function isParenthesizedTypeNode(node: Node): node is ParenthesizedTypeNode {
|
||||
return node.kind === SyntaxKind.ParenthesizedType;
|
||||
}
|
||||
|
||||
@@ -394,6 +394,10 @@ namespace ts {
|
||||
visitNode((<ConditionalTypeNode>node).trueType, visitor, isTypeNode),
|
||||
visitNode((<ConditionalTypeNode>node).falseType, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.InferType:
|
||||
return updateInferTypeNode(<InferTypeNode>node,
|
||||
visitNode((<InferTypeNode>node).typeParameter, visitor, isTypeParameterDeclaration));
|
||||
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
return updateParenthesizedType(<ParenthesizedTypeNode>node,
|
||||
visitNode((<ParenthesizedTypeNode>node).type, visitor, isTypeNode));
|
||||
|
||||
Reference in New Issue
Block a user