Add 'extends' clause to 'infer' type (#48112)

* Add 'extends' clause to 'infer' type

* Revise parse for infer..extends, improve parenthesizer

* More aggressive parens to match existing DT tests

* tests 'infer' constraint using outer type parameter

* Adds a test showing 'infer' cannot reference other 'infer' in same 'extends'

* Emit extends clause for synthetic infer typesduring declaration emit
This commit is contained in:
Ron Buckton
2022-04-05 12:35:28 -07:00
committed by GitHub
parent 6e0447fdf1
commit 7da80d79e2
56 changed files with 1948 additions and 242 deletions
+35 -6
View File
@@ -5009,7 +5009,20 @@ namespace ts {
if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) {
if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) {
context.approximateLength += (symbolName(type.symbol).length + 6);
return factory.createInferTypeNode(typeParameterToDeclarationWithConstraint(type as TypeParameter, context, /*constraintNode*/ undefined));
let constraintNode: TypeNode | undefined;
const constraint = getConstraintOfTypeParameter(type as TypeParameter);
if (constraint) {
// If the infer type has a constraint that is not the same as the constraint
// we would have normally inferred based on context, we emit the constraint
// using `infer T extends ?`. We omit inferred constraints from type references
// as they may be elided.
const inferredConstraint = getInferredTypeParameterConstraint(type as TypeParameter, /*omitTypeReferences*/ true);
if (!(inferredConstraint && isTypeIdenticalTo(constraint, inferredConstraint))) {
context.approximateLength += 9;
constraintNode = constraint && typeToTypeNodeHelper(constraint, context);
}
}
return factory.createInferTypeNode(typeParameterToDeclarationWithConstraint(type as TypeParameter, context, constraintNode));
}
if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams &&
type.flags & TypeFlags.TypeParameter &&
@@ -13257,7 +13270,7 @@ namespace ts {
return mapDefined(filter(type.symbol && type.symbol.declarations, isTypeParameterDeclaration), getEffectiveConstraintOfTypeParameter)[0];
}
function getInferredTypeParameterConstraint(typeParameter: TypeParameter) {
function getInferredTypeParameterConstraint(typeParameter: TypeParameter, omitTypeReferences?: boolean) {
let inferences: Type[] | undefined;
if (typeParameter.symbol?.declarations) {
for (const declaration of typeParameter.symbol.declarations) {
@@ -13267,7 +13280,7 @@ namespace ts {
// corresponding type parameter in 'Foo'. When multiple 'infer T' declarations are
// present, we form an intersection of the inferred constraint types.
const [childTypeParameter = declaration.parent, grandParent] = walkUpParenthesizedTypesAndGetParentAndChild(declaration.parent.parent);
if (grandParent.kind === SyntaxKind.TypeReference) {
if (grandParent.kind === SyntaxKind.TypeReference && !omitTypeReferences) {
const typeReference = grandParent as TypeReferenceNode;
const typeParameters = getTypeParametersForTypeReference(typeReference);
if (typeParameters) {
@@ -35614,6 +35627,22 @@ namespace ts {
grammarErrorOnNode(node, Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type);
}
checkSourceElement(node.typeParameter);
const symbol = getSymbolOfNode(node.typeParameter);
if (symbol.declarations && symbol.declarations.length > 1) {
const links = getSymbolLinks(symbol);
if (!links.typeParametersChecked) {
links.typeParametersChecked = true;
const typeParameter = getDeclaredTypeOfTypeParameter(symbol);
const declarations: TypeParameterDeclaration[] = getDeclarationsOfKind(symbol, SyntaxKind.TypeParameter);
if (!areTypeParametersIdentical(declarations, [typeParameter], decl => [decl])) {
// Report an error on every conflicting declaration.
const name = symbolToString(symbol);
for (const declaration of declarations) {
error(declaration.name, Diagnostics.All_declarations_of_0_must_have_identical_constraints, name);
}
}
}
}
registerForUnusedIdentifiersCheck(node);
}
@@ -39124,7 +39153,7 @@ namespace ts {
}
const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType;
if (!areTypeParametersIdentical(declarations, type.localTypeParameters!)) {
if (!areTypeParametersIdentical(declarations, type.localTypeParameters!, getEffectiveTypeParameterDeclarations)) {
// Report an error on every conflicting declaration.
const name = symbolToString(symbol);
for (const declaration of declarations) {
@@ -39134,13 +39163,13 @@ namespace ts {
}
}
function areTypeParametersIdentical(declarations: readonly (ClassDeclaration | InterfaceDeclaration)[], targetParameters: TypeParameter[]) {
function areTypeParametersIdentical<T extends DeclarationWithTypeParameters | TypeParameterDeclaration>(declarations: readonly T[], targetParameters: TypeParameter[], getTypeParameterDeclarations: (node: T) => readonly TypeParameterDeclaration[]) {
const maxTypeArgumentCount = length(targetParameters);
const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters);
for (const declaration of declarations) {
// If this declaration has too few or too many type parameters, we report an error
const sourceParameters = getEffectiveTypeParameterDeclarations(declaration);
const sourceParameters = getTypeParameterDeclarations(declaration);
const numTypeParameters = sourceParameters.length;
if (numTypeParameters < minTypeArgumentCount || numTypeParameters > maxTypeArgumentCount) {
return false;
+4
View File
@@ -3433,6 +3433,10 @@
"category": "Error",
"code": 2837
},
"All declarations of '{0}' must have identical constraints.": {
"category": "Error",
"code": 2838
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
+49 -19
View File
@@ -909,6 +909,9 @@ namespace ts {
let currentParenthesizerRule: ((node: Node) => Node) | undefined;
const { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment");
const parenthesizer = factory.parenthesizer;
const typeArgumentParenthesizerRuleSelector: OrdinalParentheizerRuleSelector<Node> = {
select: index => index === 0 ? parenthesizer.parenthesizeLeadingTypeArgument : undefined
};
const emitBinaryExpression = createEmitBinaryExpression();
reset();
@@ -2241,7 +2244,7 @@ namespace ts {
}
function emitArrayType(node: ArrayTypeNode) {
emit(node.elementType, parenthesizer.parenthesizeElementTypeOfArrayType);
emit(node.elementType, parenthesizer.parenthesizeNonArrayTypeOfPostfixType);
writePunctuation("[");
writePunctuation("]");
}
@@ -2254,7 +2257,7 @@ namespace ts {
function emitTupleType(node: TupleTypeNode) {
emitTokenWithComment(SyntaxKind.OpenBracketToken, node.pos, writePunctuation, node);
const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTupleTypeElements : ListFormat.MultiLineTupleTypeElements;
emitList(node, node.elements, flags | ListFormat.NoSpaceIfEmpty);
emitList(node, node.elements, flags | ListFormat.NoSpaceIfEmpty, parenthesizer.parenthesizeElementTypeOfTupleType);
emitTokenWithComment(SyntaxKind.CloseBracketToken, node.elements.end, writePunctuation, node);
}
@@ -2268,24 +2271,24 @@ namespace ts {
}
function emitOptionalType(node: OptionalTypeNode) {
emit(node.type, parenthesizer.parenthesizeElementTypeOfArrayType);
emit(node.type, parenthesizer.parenthesizeTypeOfOptionalType);
writePunctuation("?");
}
function emitUnionType(node: UnionTypeNode) {
emitList(node, node.types, ListFormat.UnionTypeConstituents, parenthesizer.parenthesizeMemberOfElementType);
emitList(node, node.types, ListFormat.UnionTypeConstituents, parenthesizer.parenthesizeConstituentTypeOfUnionType);
}
function emitIntersectionType(node: IntersectionTypeNode) {
emitList(node, node.types, ListFormat.IntersectionTypeConstituents, parenthesizer.parenthesizeMemberOfElementType);
emitList(node, node.types, ListFormat.IntersectionTypeConstituents, parenthesizer.parenthesizeConstituentTypeOfIntersectionType);
}
function emitConditionalType(node: ConditionalTypeNode) {
emit(node.checkType, parenthesizer.parenthesizeMemberOfConditionalType);
emit(node.checkType, parenthesizer.parenthesizeCheckTypeOfConditionalType);
writeSpace();
writeKeyword("extends");
writeSpace();
emit(node.extendsType, parenthesizer.parenthesizeMemberOfConditionalType);
emit(node.extendsType, parenthesizer.parenthesizeExtendsTypeOfConditionalType);
writeSpace();
writePunctuation("?");
writeSpace();
@@ -2315,11 +2318,15 @@ namespace ts {
function emitTypeOperator(node: TypeOperatorNode) {
writeTokenText(node.operator, writeKeyword);
writeSpace();
emit(node.type, parenthesizer.parenthesizeMemberOfElementType);
const parenthesizerRule = node.operator === SyntaxKind.ReadonlyKeyword ?
parenthesizer.parenthesizeOperandOfReadonlyTypeOperator :
parenthesizer.parenthesizeOperandOfTypeOperator;
emit(node.type, parenthesizerRule);
}
function emitIndexedAccessType(node: IndexedAccessTypeNode) {
emit(node.objectType, parenthesizer.parenthesizeMemberOfElementType);
emit(node.objectType, parenthesizer.parenthesizeNonArrayTypeOfPostfixType);
writePunctuation("[");
emit(node.indexType);
writePunctuation("]");
@@ -4256,7 +4263,7 @@ namespace ts {
}
function emitTypeArguments(parentNode: Node, typeArguments: NodeArray<TypeNode> | undefined) {
emitList(parentNode, typeArguments, ListFormat.TypeArguments, parenthesizer.parenthesizeMemberOfElementType);
emitList(parentNode, typeArguments, ListFormat.TypeArguments, typeArgumentParenthesizerRuleSelector);
}
function emitTypeParameters(parentNode: SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration | ClassDeclaration | ClassExpression, typeParameters: NodeArray<TypeParameterDeclaration> | undefined) {
@@ -4324,15 +4331,15 @@ namespace ts {
}
}
function emitList(parentNode: Node | undefined, children: NodeArray<Node> | undefined, format: ListFormat, parenthesizerRule?: (node: Node) => Node, start?: number, count?: number) {
function emitList(parentNode: Node | undefined, children: NodeArray<Node> | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector<Node>, start?: number, count?: number) {
emitNodeList(emit, parentNode, children, format, parenthesizerRule, start, count);
}
function emitExpressionList(parentNode: Node | undefined, children: NodeArray<Node> | undefined, format: ListFormat, parenthesizerRule?: (node: Expression) => Expression, start?: number, count?: number) {
function emitExpressionList(parentNode: Node | undefined, children: NodeArray<Node> | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector<Expression>, start?: number, count?: number) {
emitNodeList(emitExpression, parentNode, children, format, parenthesizerRule, start, count);
}
function emitNodeList(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parentNode: Node | undefined, children: NodeArray<Node> | undefined, format: ListFormat, parenthesizerRule: ((node: Node) => Node) | undefined, start = 0, count = children ? children.length - start : 0) {
function emitNodeList(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parentNode: Node | undefined, children: NodeArray<Node> | undefined, format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector<Node> | undefined, start = 0, count = children ? children.length - start : 0) {
const isUndefined = children === undefined;
if (isUndefined && format & ListFormat.OptionalIfUndefined) {
return;
@@ -4388,6 +4395,8 @@ namespace ts {
increaseIndent();
}
const emitListItem = getEmitListItem(emit, parenthesizerRule);
// Emit each child.
let previousSibling: Node | undefined;
let previousSourceFileTextKind: ReturnType<typeof recordBundleFileInternalSectionStart>;
@@ -4443,12 +4452,7 @@ namespace ts {
}
nextListElementPos = child.pos;
if (emit.length === 1) {
emit(child);
}
else {
emit(child, parenthesizerRule);
}
emitListItem(child, emit, parenthesizerRule, i);
if (shouldDecreaseIndentAfterEmit) {
decreaseIndent();
@@ -5890,4 +5894,30 @@ namespace ts {
CountMask = 0x0FFFFFFF, // Temp variable counter
_i = 0x10000000, // Use/preference flag for '_i'
}
interface OrdinalParentheizerRuleSelector<T extends Node> {
select(index: number): ((node: T) => T) | undefined;
}
type ParenthesizerRule<T extends Node> = (node: T) => T;
type ParenthesizerRuleOrSelector<T extends Node> = OrdinalParentheizerRuleSelector<T> | ParenthesizerRule<T>;
function emitListItemNoParenthesizer(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, _parenthesizerRule: ParenthesizerRuleOrSelector<Node> | undefined, _index: number) {
emit(node);
}
function emitListItemWithParenthesizerRuleSelector(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRuleSelector: OrdinalParentheizerRuleSelector<Node>, index: number) {
emit(node, parenthesizerRuleSelector.select(index));
}
function emitListItemWithParenthesizerRule(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: ParenthesizerRule<Node> | undefined, _index: number) {
emit(node, parenthesizerRule);
}
function getEmitListItem<T extends Node, R extends ParenthesizerRuleOrSelector<T> | undefined>(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: R): (node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: R, index: number) => void {
return emit.length === 1 ? emitListItemNoParenthesizer :
typeof parenthesizerRule === "object" ? emitListItemWithParenthesizerRuleSelector :
emitListItemWithParenthesizerRule;
}
}
+43 -21
View File
@@ -34,6 +34,8 @@ namespace ts {
const getJSDocPrimaryTypeCreateFunction = memoizeOne(<T extends JSDocType>(kind: T["kind"]) => () => createJSDocPrimaryTypeWorker(kind));
const getJSDocUnaryTypeCreateFunction = memoizeOne(<T extends JSDocType & { readonly type: TypeNode | undefined; }>(kind: T["kind"]) => (type: T["type"]) => createJSDocUnaryTypeWorker<T>(kind, type));
const getJSDocUnaryTypeUpdateFunction = memoizeOne(<T extends JSDocType & { readonly type: TypeNode | undefined; }>(kind: T["kind"]) => (node: T, type: T["type"]) => updateJSDocUnaryTypeWorker<T>(kind, node, type));
const getJSDocPrePostfixUnaryTypeCreateFunction = memoizeOne(<T extends JSDocType & { readonly type: TypeNode | undefined; readonly postfix: boolean; }>(kind: T["kind"]) => (type: T["type"], postfix?: boolean) => createJSDocPrePostfixUnaryTypeWorker<T>(kind, type, postfix));
const getJSDocPrePostfixUnaryTypeUpdateFunction = memoizeOne(<T extends JSDocType & { readonly type: TypeNode | undefined; readonly postfix: boolean; }>(kind: T["kind"]) => (node: T, type: T["type"]) => updateJSDocPrePostfixUnaryTypeWorker<T>(kind, node, type));
const getJSDocSimpleTagCreateFunction = memoizeOne(<T extends JSDocTag>(kind: T["kind"]) => (tagName: Identifier | undefined, comment?: NodeArray<JSDocComment>) => createJSDocSimpleTagWorker(kind, tagName, comment));
const getJSDocSimpleTagUpdateFunction = memoizeOne(<T extends JSDocTag>(kind: T["kind"]) => (node: T, tagName: Identifier | undefined, comment?: NodeArray<JSDocComment>) => updateJSDocSimpleTagWorker(kind, node, tagName, comment));
const getJSDocTypeLikeTagCreateFunction = memoizeOne(<T extends JSDocTag & { typeExpression?: JSDocTypeExpression }>(kind: T["kind"]) => (tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: NodeArray<JSDocComment>) => createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment));
@@ -42,6 +44,8 @@ namespace ts {
const factory: NodeFactory = {
get parenthesizer() { return parenthesizerRules(); },
get converters() { return converters(); },
baseFactory,
flags,
createNodeArray,
createNumericLiteral,
createBigIntLiteral,
@@ -317,10 +321,10 @@ namespace ts {
// lazily load factory members for JSDoc types with similar structure
get createJSDocAllType() { return getJSDocPrimaryTypeCreateFunction<JSDocAllType>(SyntaxKind.JSDocAllType); },
get createJSDocUnknownType() { return getJSDocPrimaryTypeCreateFunction<JSDocUnknownType>(SyntaxKind.JSDocUnknownType); },
get createJSDocNonNullableType() { return getJSDocUnaryTypeCreateFunction<JSDocNonNullableType>(SyntaxKind.JSDocNonNullableType); },
get updateJSDocNonNullableType() { return getJSDocUnaryTypeUpdateFunction<JSDocNonNullableType>(SyntaxKind.JSDocNonNullableType); },
get createJSDocNullableType() { return getJSDocUnaryTypeCreateFunction<JSDocNullableType>(SyntaxKind.JSDocNullableType); },
get updateJSDocNullableType() { return getJSDocUnaryTypeUpdateFunction<JSDocNullableType>(SyntaxKind.JSDocNullableType); },
get createJSDocNonNullableType() { return getJSDocPrePostfixUnaryTypeCreateFunction<JSDocNonNullableType>(SyntaxKind.JSDocNonNullableType); },
get updateJSDocNonNullableType() { return getJSDocPrePostfixUnaryTypeUpdateFunction<JSDocNonNullableType>(SyntaxKind.JSDocNonNullableType); },
get createJSDocNullableType() { return getJSDocPrePostfixUnaryTypeCreateFunction<JSDocNullableType>(SyntaxKind.JSDocNullableType); },
get updateJSDocNullableType() { return getJSDocPrePostfixUnaryTypeUpdateFunction<JSDocNullableType>(SyntaxKind.JSDocNullableType); },
get createJSDocOptionalType() { return getJSDocUnaryTypeCreateFunction<JSDocOptionalType>(SyntaxKind.JSDocOptionalType); },
get updateJSDocOptionalType() { return getJSDocUnaryTypeUpdateFunction<JSDocOptionalType>(SyntaxKind.JSDocOptionalType); },
get createJSDocVariadicType() { return getJSDocUnaryTypeCreateFunction<JSDocVariadicType>(SyntaxKind.JSDocVariadicType); },
@@ -1912,7 +1916,7 @@ namespace ts {
// @api
function createArrayTypeNode(elementType: TypeNode) {
const node = createBaseNode<ArrayTypeNode>(SyntaxKind.ArrayType);
node.elementType = parenthesizerRules().parenthesizeElementTypeOfArrayType(elementType);
node.elementType = parenthesizerRules().parenthesizeNonArrayTypeOfPostfixType(elementType);
node.transformFlags = TransformFlags.ContainsTypeScript;
return node;
}
@@ -1927,7 +1931,7 @@ namespace ts {
// @api
function createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]) {
const node = createBaseNode<TupleTypeNode>(SyntaxKind.TupleType);
node.elements = createNodeArray(elements);
node.elements = createNodeArray(parenthesizerRules().parenthesizeElementTypesOfTupleType(elements));
node.transformFlags = TransformFlags.ContainsTypeScript;
return node;
}
@@ -1963,7 +1967,7 @@ namespace ts {
// @api
function createOptionalTypeNode(type: TypeNode) {
const node = createBaseNode<OptionalTypeNode>(SyntaxKind.OptionalType);
node.type = parenthesizerRules().parenthesizeElementTypeOfArrayType(type);
node.type = parenthesizerRules().parenthesizeTypeOfOptionalType(type);
node.transformFlags = TransformFlags.ContainsTypeScript;
return node;
}
@@ -1990,44 +1994,44 @@ namespace ts {
: node;
}
function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: readonly TypeNode[]) {
function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: readonly TypeNode[], parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[]) {
const node = createBaseNode<UnionTypeNode | IntersectionTypeNode>(kind);
node.types = parenthesizerRules().parenthesizeConstituentTypesOfUnionOrIntersectionType(types);
node.types = factory.createNodeArray(parenthesize(types));
node.transformFlags = TransformFlags.ContainsTypeScript;
return node;
}
function updateUnionOrIntersectionTypeNode<T extends UnionOrIntersectionTypeNode>(node: T, types: NodeArray<TypeNode>): T {
function updateUnionOrIntersectionTypeNode<T extends UnionOrIntersectionTypeNode>(node: T, types: NodeArray<TypeNode>, parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[]): T {
return node.types !== types
? update(createUnionOrIntersectionTypeNode(node.kind, types) as T, node)
? update(createUnionOrIntersectionTypeNode(node.kind, types, parenthesize) as T, node)
: node;
}
// @api
function createUnionTypeNode(types: readonly TypeNode[]): UnionTypeNode {
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types) as UnionTypeNode;
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types, parenthesizerRules().parenthesizeConstituentTypesOfUnionType) as UnionTypeNode;
}
// @api
function updateUnionTypeNode(node: UnionTypeNode, types: NodeArray<TypeNode>) {
return updateUnionOrIntersectionTypeNode(node, types);
return updateUnionOrIntersectionTypeNode(node, types, parenthesizerRules().parenthesizeConstituentTypesOfUnionType);
}
// @api
function createIntersectionTypeNode(types: readonly TypeNode[]): IntersectionTypeNode {
return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, types) as IntersectionTypeNode;
return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, types, parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType) as IntersectionTypeNode;
}
// @api
function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray<TypeNode>) {
return updateUnionOrIntersectionTypeNode(node, types);
return updateUnionOrIntersectionTypeNode(node, types, parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType);
}
// @api
function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) {
const node = createBaseNode<ConditionalTypeNode>(SyntaxKind.ConditionalType);
node.checkType = parenthesizerRules().parenthesizeMemberOfConditionalType(checkType);
node.extendsType = parenthesizerRules().parenthesizeMemberOfConditionalType(extendsType);
node.checkType = parenthesizerRules().parenthesizeCheckTypeOfConditionalType(checkType);
node.extendsType = parenthesizerRules().parenthesizeExtendsTypeOfConditionalType(extendsType);
node.trueType = trueType;
node.falseType = falseType;
node.transformFlags = TransformFlags.ContainsTypeScript;
@@ -2154,7 +2158,9 @@ namespace ts {
function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode {
const node = createBaseNode<TypeOperatorNode>(SyntaxKind.TypeOperator);
node.operator = operator;
node.type = parenthesizerRules().parenthesizeMemberOfElementType(type);
node.type = operator === SyntaxKind.ReadonlyKeyword ?
parenthesizerRules().parenthesizeOperandOfReadonlyTypeOperator(type) :
parenthesizerRules().parenthesizeOperandOfTypeOperator(type);
node.transformFlags = TransformFlags.ContainsTypeScript;
return node;
}
@@ -2169,7 +2175,7 @@ namespace ts {
// @api
function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) {
const node = createBaseNode<IndexedAccessTypeNode>(SyntaxKind.IndexedAccessType);
node.objectType = parenthesizerRules().parenthesizeMemberOfElementType(objectType);
node.objectType = parenthesizerRules().parenthesizeNonArrayTypeOfPostfixType(objectType);
node.indexType = indexType;
node.transformFlags = TransformFlags.ContainsTypeScript;
return node;
@@ -4360,12 +4366,21 @@ namespace ts {
}
// @api
// createJSDocNonNullableType
// createJSDocNullableType
// createJSDocNonNullableType
function createJSDocPrePostfixUnaryTypeWorker<T extends JSDocType & { readonly type: TypeNode | undefined; readonly postfix: boolean }>(kind: T["kind"], type: T["type"], postfix = false): T {
const node = createJSDocUnaryTypeWorker(
kind,
postfix ? type && parenthesizerRules().parenthesizeNonArrayTypeOfPostfixType(type) : type
) as Mutable<T>;
node.postfix = postfix;
return node;
}
// @api
// createJSDocOptionalType
// createJSDocVariadicType
// createJSDocNamepathType
function createJSDocUnaryTypeWorker<T extends JSDocType & { readonly type: TypeNode | undefined; }>(kind: T["kind"], type: T["type"]): T {
const node = createBaseNode<T>(kind);
node.type = type;
@@ -4375,6 +4390,13 @@ namespace ts {
// @api
// updateJSDocNonNullableType
// updateJSDocNullableType
function updateJSDocPrePostfixUnaryTypeWorker<T extends JSDocType & { readonly type: TypeNode | undefined; readonly postfix: boolean; }>(kind: T["kind"], node: T, type: T["type"]): T {
return node.type !== type
? update(createJSDocPrePostfixUnaryTypeWorker(kind, type, node.postfix), node)
: node;
}
// @api
// updateJSDocOptionalType
// updateJSDocVariadicType
// updateJSDocNamepathType
+205 -26
View File
@@ -25,11 +25,20 @@ namespace ts {
parenthesizeExpressionForDisallowedComma,
parenthesizeExpressionOfExpressionStatement,
parenthesizeConciseBodyOfArrowFunction,
parenthesizeMemberOfConditionalType,
parenthesizeMemberOfElementType,
parenthesizeElementTypeOfArrayType,
parenthesizeConstituentTypesOfUnionOrIntersectionType,
parenthesizeCheckTypeOfConditionalType,
parenthesizeExtendsTypeOfConditionalType,
parenthesizeConstituentTypesOfUnionType,
parenthesizeConstituentTypeOfUnionType,
parenthesizeConstituentTypesOfIntersectionType,
parenthesizeConstituentTypeOfIntersectionType,
parenthesizeOperandOfTypeOperator,
parenthesizeOperandOfReadonlyTypeOperator,
parenthesizeNonArrayTypeOfPostfixType,
parenthesizeElementTypesOfTupleType,
parenthesizeElementTypeOfTupleType,
parenthesizeTypeOfOptionalType,
parenthesizeTypeArguments,
parenthesizeLeadingTypeArgument,
};
function getParenthesizeLeftSideOfBinaryForOperator(operatorKind: BinaryOperator) {
@@ -388,38 +397,199 @@ namespace ts {
return body;
}
function parenthesizeMemberOfConditionalType(member: TypeNode): TypeNode {
return member.kind === SyntaxKind.ConditionalType ? factory.createParenthesizedType(member) : member;
}
// Type[Extends] :
// FunctionOrConstructorType
// ConditionalType[?Extends]
function parenthesizeMemberOfElementType(member: TypeNode): TypeNode {
switch (member.kind) {
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
// ConditionalType[Extends] :
// UnionType[?Extends]
// [~Extends] UnionType[~Extends] `extends` Type[+Extends] `?` Type[~Extends] `:` Type[~Extends]
//
// - The check type (the `UnionType`, above) does not allow function, constructor, or conditional types (they must be parenthesized)
// - The extends type (the first `Type`, above) does not allow conditional types (they must be parenthesized). Function and constructor types are fine.
// - The true and false branch types (the second and third `Type` non-terminals, above) allow any type
function parenthesizeCheckTypeOfConditionalType(checkType: TypeNode): TypeNode {
switch (checkType.kind) {
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
return factory.createParenthesizedType(member);
case SyntaxKind.ConditionalType:
return factory.createParenthesizedType(checkType);
}
return parenthesizeMemberOfConditionalType(member);
return checkType;
}
function parenthesizeElementTypeOfArrayType(member: TypeNode): TypeNode {
switch (member.kind) {
case SyntaxKind.TypeQuery:
function parenthesizeExtendsTypeOfConditionalType(extendsType: TypeNode): TypeNode {
switch (extendsType.kind) {
case SyntaxKind.ConditionalType:
return factory.createParenthesizedType(extendsType);
}
return extendsType;
}
// UnionType[Extends] :
// `|`? IntersectionType[?Extends]
// UnionType[?Extends] `|` IntersectionType[?Extends]
//
// - A union type constituent has the same precedence as the check type of a conditional type
function parenthesizeConstituentTypeOfUnionType(type: TypeNode) {
switch (type.kind) {
case SyntaxKind.UnionType: // Not strictly necessary, but a union containing a union should have been flattened
case SyntaxKind.IntersectionType: // Not strictly necessary, but makes generated output more readable and avoids breaks in DT tests
return factory.createParenthesizedType(type);
}
return parenthesizeCheckTypeOfConditionalType(type);
}
function parenthesizeConstituentTypesOfUnionType(members: readonly TypeNode[]): NodeArray<TypeNode> {
return factory.createNodeArray(sameMap(members, parenthesizeConstituentTypeOfUnionType));
}
// IntersectionType[Extends] :
// `&`? TypeOperator[?Extends]
// IntersectionType[?Extends] `&` TypeOperator[?Extends]
//
// - An intersection type constituent does not allow function, constructor, conditional, or union types (they must be parenthesized)
function parenthesizeConstituentTypeOfIntersectionType(type: TypeNode) {
switch (type.kind) {
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType: // Not strictly necessary, but an intersection containing an intersection should have been flattened
return factory.createParenthesizedType(type);
}
return parenthesizeConstituentTypeOfUnionType(type);
}
function parenthesizeConstituentTypesOfIntersectionType(members: readonly TypeNode[]): NodeArray<TypeNode> {
return factory.createNodeArray(sameMap(members, parenthesizeConstituentTypeOfIntersectionType));
}
// TypeOperator[Extends] :
// PostfixType
// InferType[?Extends]
// `keyof` TypeOperator[?Extends]
// `unique` TypeOperator[?Extends]
// `readonly` TypeOperator[?Extends]
//
function parenthesizeOperandOfTypeOperator(type: TypeNode) {
switch (type.kind) {
case SyntaxKind.IntersectionType:
return factory.createParenthesizedType(type);
}
return parenthesizeConstituentTypeOfIntersectionType(type);
}
function parenthesizeOperandOfReadonlyTypeOperator(type: TypeNode) {
switch (type.kind) {
case SyntaxKind.TypeOperator:
case SyntaxKind.InferType:
return factory.createParenthesizedType(member);
return factory.createParenthesizedType(type);
}
return parenthesizeMemberOfElementType(member);
return parenthesizeOperandOfTypeOperator(type);
}
function parenthesizeConstituentTypesOfUnionOrIntersectionType(members: readonly TypeNode[]): NodeArray<TypeNode> {
return factory.createNodeArray(sameMap(members, parenthesizeMemberOfElementType));
// PostfixType :
// NonArrayType
// NonArrayType [no LineTerminator here] `!` // JSDoc
// NonArrayType [no LineTerminator here] `?` // JSDoc
// IndexedAccessType
// ArrayType
//
// IndexedAccessType :
// NonArrayType `[` Type[~Extends] `]`
//
// ArrayType :
// NonArrayType `[` `]`
//
function parenthesizeNonArrayTypeOfPostfixType(type: TypeNode) {
switch (type.kind) {
case SyntaxKind.InferType:
case SyntaxKind.TypeOperator:
case SyntaxKind.TypeQuery: // Not strictly necessary, but makes generated output more readable and avoids breaks in DT tests
return factory.createParenthesizedType(type);
}
return parenthesizeOperandOfTypeOperator(type);
}
// TupleType :
// `[` Elision? `]`
// `[` NamedTupleElementTypes `]`
// `[` NamedTupleElementTypes `,` Elision? `]`
// `[` TupleElementTypes `]`
// `[` TupleElementTypes `,` Elision? `]`
//
// NamedTupleElementTypes :
// Elision? NamedTupleMember
// NamedTupleElementTypes `,` Elision? NamedTupleMember
//
// NamedTupleMember :
// Identifier `?`? `:` Type[~Extends]
// `...` Identifier `:` Type[~Extends]
//
// TupleElementTypes :
// Elision? TupleElementType
// TupleElementTypes `,` Elision? TupleElementType
//
// TupleElementType :
// Type[~Extends] // NOTE: Needs cover grammar to disallow JSDoc postfix-optional
// OptionalType
// RestType
//
// OptionalType :
// Type[~Extends] `?` // NOTE: Needs cover grammar to disallow JSDoc postfix-optional
//
// RestType :
// `...` Type[~Extends]
//
function parenthesizeElementTypesOfTupleType(types: readonly (TypeNode | NamedTupleMember)[]): NodeArray<TypeNode> {
return factory.createNodeArray(sameMap(types, parenthesizeElementTypeOfTupleType));
}
function parenthesizeElementTypeOfTupleType(type: TypeNode | NamedTupleMember): TypeNode {
if (hasJSDocPostfixQuestion(type)) return factory.createParenthesizedType(type);
return type;
}
function hasJSDocPostfixQuestion(type: TypeNode | NamedTupleMember): boolean {
if (isJSDocNullableType(type)) return type.postfix;
if (isNamedTupleMember(type)) return hasJSDocPostfixQuestion(type.type);
if (isFunctionTypeNode(type) || isConstructorTypeNode(type) || isTypeOperatorNode(type)) return hasJSDocPostfixQuestion(type.type);
if (isConditionalTypeNode(type)) return hasJSDocPostfixQuestion(type.falseType);
if (isUnionTypeNode(type)) return hasJSDocPostfixQuestion(last(type.types));
if (isIntersectionTypeNode(type)) return hasJSDocPostfixQuestion(last(type.types));
if (isInferTypeNode(type)) return !!type.typeParameter.constraint && hasJSDocPostfixQuestion(type.typeParameter.constraint);
return false;
}
function parenthesizeTypeOfOptionalType(type: TypeNode): TypeNode {
if (hasJSDocPostfixQuestion(type)) return factory.createParenthesizedType(type);
return parenthesizeNonArrayTypeOfPostfixType(type);
}
// function parenthesizeMemberOfElementType(member: TypeNode): TypeNode {
// switch (member.kind) {
// case SyntaxKind.UnionType:
// case SyntaxKind.IntersectionType:
// case SyntaxKind.FunctionType:
// case SyntaxKind.ConstructorType:
// return factory.createParenthesizedType(member);
// }
// return parenthesizeMemberOfConditionalType(member);
// }
// function parenthesizeElementTypeOfArrayType(member: TypeNode): TypeNode {
// switch (member.kind) {
// case SyntaxKind.TypeQuery:
// case SyntaxKind.TypeOperator:
// case SyntaxKind.InferType:
// return factory.createParenthesizedType(member);
// }
// return parenthesizeMemberOfElementType(member);
// }
function parenthesizeLeadingTypeArgument(node: TypeNode) {
return isFunctionOrConstructorTypeNode(node) && node.typeParameters ? factory.createParenthesizedType(node) : node;
}
function parenthesizeOrdinalTypeArgument(node: TypeNode, i: number) {
return i === 0 && isFunctionOrConstructorTypeNode(node) && node.typeParameters ? factory.createParenthesizedType(node) : node;
return i === 0 ? parenthesizeLeadingTypeArgument(node) : node;
}
function parenthesizeTypeArguments(typeArguments: NodeArray<TypeNode> | undefined): NodeArray<TypeNode> | undefined {
@@ -446,10 +616,19 @@ namespace ts {
parenthesizeExpressionForDisallowedComma: identity,
parenthesizeExpressionOfExpressionStatement: identity,
parenthesizeConciseBodyOfArrowFunction: identity,
parenthesizeMemberOfConditionalType: identity,
parenthesizeMemberOfElementType: identity,
parenthesizeElementTypeOfArrayType: identity,
parenthesizeConstituentTypesOfUnionOrIntersectionType: nodes => cast(nodes, isNodeArray),
parenthesizeCheckTypeOfConditionalType: identity,
parenthesizeExtendsTypeOfConditionalType: identity,
parenthesizeConstituentTypesOfUnionType: nodes => cast(nodes, isNodeArray),
parenthesizeConstituentTypeOfUnionType: identity,
parenthesizeConstituentTypesOfIntersectionType: nodes => cast(nodes, isNodeArray),
parenthesizeConstituentTypeOfIntersectionType: identity,
parenthesizeOperandOfTypeOperator: identity,
parenthesizeOperandOfReadonlyTypeOperator: identity,
parenthesizeNonArrayTypeOfPostfixType: identity,
parenthesizeElementTypesOfTupleType: nodes => cast(nodes, isNodeArray),
parenthesizeElementTypeOfTupleType: identity,
parenthesizeTypeOfOptionalType: identity,
parenthesizeTypeArguments: nodes => nodes && cast(nodes, isNodeArray),
parenthesizeLeadingTypeArgument: identity,
};
}
+39 -25
View File
@@ -1391,6 +1391,14 @@ namespace ts {
return doInsideOfContext(NodeFlags.DisallowInContext, func);
}
function allowConditionalTypesAnd<T>(func: () => T): T {
return doOutsideOfContext(NodeFlags.DisallowConditionalTypesContext, func);
}
function disallowConditionalTypesAnd<T>(func: () => T): T {
return doInsideOfContext(NodeFlags.DisallowConditionalTypesContext, func);
}
function doInYieldContext<T>(func: () => T): T {
return doInsideOfContext(NodeFlags.YieldContext, func);
}
@@ -1427,6 +1435,10 @@ namespace ts {
return inContext(NodeFlags.DisallowInContext);
}
function inDisallowConditionalTypesContext() {
return inContext(NodeFlags.DisallowConditionalTypesContext);
}
function inDecoratorContext() {
return inContext(NodeFlags.DecoratorContext);
}
@@ -3073,7 +3085,7 @@ namespace ts {
function parseJSDocNonNullableType(): TypeNode {
const pos = getNodePos();
nextToken();
return finishNode(factory.createJSDocNonNullableType(parseNonArrayType()), pos);
return finishNode(factory.createJSDocNonNullableType(parseNonArrayType(), /*postfix*/ false), pos);
}
function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType {
@@ -3100,7 +3112,7 @@ namespace ts {
return finishNode(factory.createJSDocUnknownType(), pos);
}
else {
return finishNode(factory.createJSDocNullableType(parseType()), pos);
return finishNode(factory.createJSDocNullableType(parseType(), /*postfix*/ false), pos);
}
}
@@ -3323,7 +3335,7 @@ namespace ts {
function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined;
function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) {
if (shouldParseReturnType(returnToken, isType)) {
return parseTypeOrTypePredicate();
return allowConditionalTypesAnd(parseTypeOrTypePredicate);
}
}
@@ -3948,7 +3960,7 @@ namespace ts {
switch (token()) {
case SyntaxKind.ExclamationToken:
nextToken();
type = finishNode(factory.createJSDocNonNullableType(type), pos);
type = finishNode(factory.createJSDocNonNullableType(type, /*postfix*/ true), pos);
break;
case SyntaxKind.QuestionToken:
// If next token is start of a type we have a conditional type
@@ -3956,7 +3968,7 @@ namespace ts {
return type;
}
nextToken();
type = finishNode(factory.createJSDocNullableType(type), pos);
type = finishNode(factory.createJSDocNullableType(type, /*postfix*/ true), pos);
break;
case SyntaxKind.OpenBracketToken:
parseExpected(SyntaxKind.OpenBracketToken);
@@ -3983,17 +3995,21 @@ namespace ts {
return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos);
}
function parseTypeParameterOfInferType() {
function tryParseConstraintOfInferType() {
if (parseOptional(SyntaxKind.ExtendsKeyword)) {
const constraint = disallowConditionalTypesAnd(parseType);
if (inDisallowConditionalTypesContext() || token() !== SyntaxKind.QuestionToken) {
return constraint;
}
}
}
function parseTypeParameterOfInferType(): TypeParameterDeclaration {
const pos = getNodePos();
return finishNode(
factory.createTypeParameterDeclaration(
/*modifiers*/ undefined,
parseIdentifier(),
/*constraint*/ undefined,
/*defaultType*/ undefined
),
pos
);
const name = parseIdentifier();
const constraint = tryParse(tryParseConstraintOfInferType);
const node = factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, constraint);
return finishNode(node, pos);
}
function parseInferType(): InferTypeNode {
@@ -4012,7 +4028,7 @@ namespace ts {
case SyntaxKind.InferKeyword:
return parseInferType();
}
return parsePostfixTypeOrHigher();
return allowConditionalTypesAnd(parsePostfixTypeOrHigher);
}
function parseFunctionOrConstructorTypeToError(
@@ -4161,24 +4177,22 @@ namespace ts {
}
function parseType(): TypeNode {
// The rules about 'yield' only apply to actual code/expression contexts. They don't
// apply to 'type' contexts. So we disable these parameters here before moving on.
return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseTypeWorker);
}
if (contextFlags & NodeFlags.TypeExcludesFlags) {
return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseType);
}
function parseTypeWorker(noConditionalTypes?: boolean): TypeNode {
if (isStartOfFunctionTypeOrConstructorType()) {
return parseFunctionOrConstructorType();
}
const pos = getNodePos();
const type = parseUnionTypeOrHigher();
if (!noConditionalTypes && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) {
if (!inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) {
// The type following 'extends' is not permitted to be another conditional type
const extendsType = parseTypeWorker(/*noConditionalTypes*/ true);
const extendsType = disallowConditionalTypesAnd(parseType);
parseExpected(SyntaxKind.QuestionToken);
const trueType = parseTypeWorker();
const trueType = allowConditionalTypesAnd(parseType);
parseExpected(SyntaxKind.ColonToken);
const falseType = parseTypeWorker();
const falseType = allowConditionalTypesAnd(parseType);
return finishNode(factory.createConditionalTypeNode(type, extendsType, trueType, falseType), pos);
}
return type;
+33 -19
View File
@@ -763,10 +763,11 @@ namespace ts {
YieldContext = 1 << 13, // If node was parsed in the 'yield' context created when parsing a generator
DecoratorContext = 1 << 14, // If node was parsed as part of a decorator
AwaitContext = 1 << 15, // If node was parsed in the 'await' context created when parsing an async function
ThisNodeHasError = 1 << 16, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 17, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 18, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 19, // If we've computed data from children and cached it in this node
DisallowConditionalTypesContext = 1 << 16, // If node was parsed in a context where conditional types are not allowed
ThisNodeHasError = 1 << 17, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 18, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 19, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 20, // If we've computed data from children and cached it in this node
// These flags will be set when the parser encounters a dynamic import expression or 'import.meta' to avoid
// walking the tree if the flags are not set. However, these flags are just a approximation
@@ -777,15 +778,15 @@ namespace ts {
// removal, it is likely that users will add the import anyway.
// The advantage of this approach is its simplicity. For the case of batch compilation,
// we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used.
/* @internal */ PossiblyContainsDynamicImport = 1 << 20,
/* @internal */ PossiblyContainsImportMeta = 1 << 21,
/* @internal */ PossiblyContainsDynamicImport = 1 << 21,
/* @internal */ PossiblyContainsImportMeta = 1 << 22,
JSDoc = 1 << 22, // If node was parsed inside jsdoc
/* @internal */ Ambient = 1 << 23, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier.
/* @internal */ InWithStatement = 1 << 24, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
JsonFile = 1 << 25, // If node was parsed in a Json
/* @internal */ TypeCached = 1 << 26, // If a type was cached for node at any point
/* @internal */ Deprecated = 1 << 27, // If has '@deprecated' JSDoc tag
JSDoc = 1 << 23, // If node was parsed inside jsdoc
/* @internal */ Ambient = 1 << 24, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier.
/* @internal */ InWithStatement = 1 << 25, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
JsonFile = 1 << 26, // If node was parsed in a Json
/* @internal */ TypeCached = 1 << 27, // If a type was cached for node at any point
/* @internal */ Deprecated = 1 << 28, // If has '@deprecated' JSDoc tag
BlockScoped = Let | Const,
@@ -793,7 +794,7 @@ namespace ts {
ReachabilityAndEmitFlags = ReachabilityCheckFlags | HasAsyncFunctions,
// Parsing context flags
ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement | Ambient,
ContextFlags = DisallowInContext | DisallowConditionalTypesContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement | Ambient,
// Exclude these flags when parsing a Type
TypeExcludesFlags = YieldContext | AwaitContext,
@@ -3234,11 +3235,13 @@ namespace ts {
export interface JSDocNonNullableType extends JSDocType {
readonly kind: SyntaxKind.JSDocNonNullableType;
readonly type: TypeNode;
readonly postfix: boolean;
}
export interface JSDocNullableType extends JSDocType {
readonly kind: SyntaxKind.JSDocNullableType;
readonly type: TypeNode;
readonly postfix: boolean;
}
export interface JSDocOptionalType extends JSDocType {
@@ -7129,10 +7132,19 @@ namespace ts {
parenthesizeExpressionOfExpressionStatement(expression: Expression): Expression;
parenthesizeConciseBodyOfArrowFunction(body: Expression): Expression;
parenthesizeConciseBodyOfArrowFunction(body: ConciseBody): ConciseBody;
parenthesizeMemberOfConditionalType(member: TypeNode): TypeNode;
parenthesizeMemberOfElementType(member: TypeNode): TypeNode;
parenthesizeElementTypeOfArrayType(member: TypeNode): TypeNode;
parenthesizeConstituentTypesOfUnionOrIntersectionType(members: readonly TypeNode[]): NodeArray<TypeNode>;
parenthesizeCheckTypeOfConditionalType(type: TypeNode): TypeNode;
parenthesizeExtendsTypeOfConditionalType(type: TypeNode): TypeNode;
parenthesizeOperandOfTypeOperator(type: TypeNode): TypeNode;
parenthesizeOperandOfReadonlyTypeOperator(type: TypeNode): TypeNode;
parenthesizeNonArrayTypeOfPostfixType(type: TypeNode): TypeNode;
parenthesizeElementTypesOfTupleType(types: readonly (TypeNode | NamedTupleMember)[]): NodeArray<TypeNode>;
parenthesizeElementTypeOfTupleType(type: TypeNode | NamedTupleMember): TypeNode | NamedTupleMember;
parenthesizeTypeOfOptionalType(type: TypeNode): TypeNode;
parenthesizeConstituentTypeOfUnionType(type: TypeNode): TypeNode;
parenthesizeConstituentTypesOfUnionType(constituents: readonly TypeNode[]): NodeArray<TypeNode>;
parenthesizeConstituentTypeOfIntersectionType(type: TypeNode): TypeNode;
parenthesizeConstituentTypesOfIntersectionType(constituents: readonly TypeNode[]): NodeArray<TypeNode>;
parenthesizeLeadingTypeArgument(typeNode: TypeNode): TypeNode;
parenthesizeTypeArguments(typeParameters: readonly TypeNode[] | undefined): NodeArray<TypeNode> | undefined;
}
@@ -7151,6 +7163,8 @@ namespace ts {
export interface NodeFactory {
/* @internal */ readonly parenthesizer: ParenthesizerRules;
/* @internal */ readonly converters: NodeConverters;
/* @internal */ readonly baseFactory: BaseNodeFactory;
/* @internal */ readonly flags: NodeFactoryFlags;
createNodeArray<T extends Node>(elements?: readonly T[], hasTrailingComma?: boolean): NodeArray<T>;
//
@@ -7549,9 +7563,9 @@ namespace ts {
createJSDocAllType(): JSDocAllType;
createJSDocUnknownType(): JSDocUnknownType;
createJSDocNonNullableType(type: TypeNode): JSDocNonNullableType;
createJSDocNonNullableType(type: TypeNode, postfix?: boolean): JSDocNonNullableType;
updateJSDocNonNullableType(node: JSDocNonNullableType, type: TypeNode): JSDocNonNullableType;
createJSDocNullableType(type: TypeNode): JSDocNullableType;
createJSDocNullableType(type: TypeNode, postfix?: boolean): JSDocNullableType;
updateJSDocNullableType(node: JSDocNullableType, type: TypeNode): JSDocNullableType;
createJSDocOptionalType(type: TypeNode): JSDocOptionalType;
updateJSDocOptionalType(node: JSDocOptionalType, type: TypeNode): JSDocOptionalType;
+10 -1
View File
@@ -1119,8 +1119,17 @@ namespace ts.textChanges {
return skipTrivia(s, 0) === s.length;
}
// A transformation context that won't perform parenthesization, as some parenthesization rules
// are more aggressive than is strictly necessary.
const textChangesTransformationContext: TransformationContext = {
...nullTransformationContext,
factory: createNodeFactory(
nullTransformationContext.factory.flags | NodeFactoryFlags.NoParenthesizerRules,
nullTransformationContext.factory.baseFactory),
};
export function assignPositionsToNode(node: Node): Node {
const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode);
const visited = visitEachChild(node, assignPositionsToNode, textChangesTransformationContext, assignPositionsToNodeArray, assignPositionsToNode);
// create proxy node for non synthesized nodes
const newNode = nodeIsSynthesized(visited) ? visited : Object.create(visited) as Node;
setTextRangePosEnd(newNode, getPos(node), getEnd(node));
@@ -12,5 +12,6 @@
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 1
}
},
"postfix": false
}
@@ -12,5 +12,6 @@
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 1
}
},
"postfix": true
}
@@ -12,5 +12,6 @@
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 1
}
},
"postfix": false
}
@@ -12,5 +12,6 @@
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 1
}
},
"postfix": true
}
@@ -12,7 +12,7 @@ enum E { A, B, C, "non identifier" }
>A : E.A
>B : E.B
>C : E.C
>"non identifier" : typeof E["non identifier"]
>"non identifier" : (typeof E)["non identifier"]
const c1 = "abc";
>c1 : "abc"
@@ -54,8 +54,8 @@ const c8 = E.A;
>A : E.A
const c8b = E["non identifier"];
>c8b : typeof E["non identifier"]
>E["non identifier"] : typeof E["non identifier"]
>c8b : (typeof E)["non identifier"]
>E["non identifier"] : (typeof E)["non identifier"]
>E : typeof E
>"non identifier" : "non identifier"
+12 -9
View File
@@ -523,16 +523,17 @@ declare namespace ts {
YieldContext = 8192,
DecoratorContext = 16384,
AwaitContext = 32768,
ThisNodeHasError = 65536,
JavaScriptFile = 131072,
ThisNodeOrAnySubNodesHasError = 262144,
HasAggregatedChildData = 524288,
JSDoc = 4194304,
JsonFile = 33554432,
DisallowConditionalTypesContext = 65536,
ThisNodeHasError = 131072,
JavaScriptFile = 262144,
ThisNodeOrAnySubNodesHasError = 524288,
HasAggregatedChildData = 1048576,
JSDoc = 8388608,
JsonFile = 67108864,
BlockScoped = 3,
ReachabilityCheckFlags = 768,
ReachabilityAndEmitFlags = 2816,
ContextFlags = 25358336,
ContextFlags = 50720768,
TypeExcludesFlags = 40960,
}
export enum ModifierFlags {
@@ -1805,10 +1806,12 @@ declare namespace ts {
export interface JSDocNonNullableType extends JSDocType {
readonly kind: SyntaxKind.JSDocNonNullableType;
readonly type: TypeNode;
readonly postfix: boolean;
}
export interface JSDocNullableType extends JSDocType {
readonly kind: SyntaxKind.JSDocNullableType;
readonly type: TypeNode;
readonly postfix: boolean;
}
export interface JSDocOptionalType extends JSDocType {
readonly kind: SyntaxKind.JSDocOptionalType;
@@ -3654,9 +3657,9 @@ declare namespace ts {
updateExternalModuleReference(node: ExternalModuleReference, expression: Expression): ExternalModuleReference;
createJSDocAllType(): JSDocAllType;
createJSDocUnknownType(): JSDocUnknownType;
createJSDocNonNullableType(type: TypeNode): JSDocNonNullableType;
createJSDocNonNullableType(type: TypeNode, postfix?: boolean): JSDocNonNullableType;
updateJSDocNonNullableType(node: JSDocNonNullableType, type: TypeNode): JSDocNonNullableType;
createJSDocNullableType(type: TypeNode): JSDocNullableType;
createJSDocNullableType(type: TypeNode, postfix?: boolean): JSDocNullableType;
updateJSDocNullableType(node: JSDocNullableType, type: TypeNode): JSDocNullableType;
createJSDocOptionalType(type: TypeNode): JSDocOptionalType;
updateJSDocOptionalType(node: JSDocOptionalType, type: TypeNode): JSDocOptionalType;
+12 -9
View File
@@ -523,16 +523,17 @@ declare namespace ts {
YieldContext = 8192,
DecoratorContext = 16384,
AwaitContext = 32768,
ThisNodeHasError = 65536,
JavaScriptFile = 131072,
ThisNodeOrAnySubNodesHasError = 262144,
HasAggregatedChildData = 524288,
JSDoc = 4194304,
JsonFile = 33554432,
DisallowConditionalTypesContext = 65536,
ThisNodeHasError = 131072,
JavaScriptFile = 262144,
ThisNodeOrAnySubNodesHasError = 524288,
HasAggregatedChildData = 1048576,
JSDoc = 8388608,
JsonFile = 67108864,
BlockScoped = 3,
ReachabilityCheckFlags = 768,
ReachabilityAndEmitFlags = 2816,
ContextFlags = 25358336,
ContextFlags = 50720768,
TypeExcludesFlags = 40960,
}
export enum ModifierFlags {
@@ -1805,10 +1806,12 @@ declare namespace ts {
export interface JSDocNonNullableType extends JSDocType {
readonly kind: SyntaxKind.JSDocNonNullableType;
readonly type: TypeNode;
readonly postfix: boolean;
}
export interface JSDocNullableType extends JSDocType {
readonly kind: SyntaxKind.JSDocNullableType;
readonly type: TypeNode;
readonly postfix: boolean;
}
export interface JSDocOptionalType extends JSDocType {
readonly kind: SyntaxKind.JSDocOptionalType;
@@ -3654,9 +3657,9 @@ declare namespace ts {
updateExternalModuleReference(node: ExternalModuleReference, expression: Expression): ExternalModuleReference;
createJSDocAllType(): JSDocAllType;
createJSDocUnknownType(): JSDocUnknownType;
createJSDocNonNullableType(type: TypeNode): JSDocNonNullableType;
createJSDocNonNullableType(type: TypeNode, postfix?: boolean): JSDocNonNullableType;
updateJSDocNonNullableType(node: JSDocNonNullableType, type: TypeNode): JSDocNonNullableType;
createJSDocNullableType(type: TypeNode): JSDocNullableType;
createJSDocNullableType(type: TypeNode, postfix?: boolean): JSDocNullableType;
updateJSDocNullableType(node: JSDocNullableType, type: TypeNode): JSDocNullableType;
createJSDocOptionalType(type: TypeNode): JSDocOptionalType;
updateJSDocOptionalType(node: JSDocOptionalType, type: TypeNode): JSDocOptionalType;
@@ -5,7 +5,7 @@ enum ENUM1 { A, B, "" };
>ENUM1 : ENUM1
>A : ENUM1.A
>B : ENUM1.B
>"" : typeof ENUM1[""]
>"" : (typeof ENUM1)[""]
// enum type var
var ResultIsNumber1 = ~ENUM1;
+14 -14
View File
@@ -184,25 +184,25 @@ const enum Comments {
>Comments : Comments
"//",
>"//" : typeof Comments["//"]
>"//" : (typeof Comments)["//"]
"/*",
>"/*" : typeof Comments["/*"]
>"/*" : (typeof Comments)["/*"]
"*/",
>"*/" : typeof Comments["*/"]
>"*/" : (typeof Comments)["*/"]
"///",
>"///" : typeof Comments["///"]
>"///" : (typeof Comments)["///"]
"#",
>"#" : typeof Comments["#"]
>"#" : (typeof Comments)["#"]
"<!--",
>"<!--" : typeof Comments["<!--"]
>"<!--" : (typeof Comments)["<!--"]
"-->",
>"-->" : typeof Comments["-->"]
>"-->" : (typeof Comments)["-->"]
}
module A {
@@ -624,37 +624,37 @@ function baz(c: Comments) {
>c : Comments
case Comments["//"]:
>Comments["//"] : typeof Comments["//"]
>Comments["//"] : (typeof Comments)["//"]
>Comments : typeof Comments
>"//" : "//"
case Comments["/*"]:
>Comments["/*"] : typeof Comments["/*"]
>Comments["/*"] : (typeof Comments)["/*"]
>Comments : typeof Comments
>"/*" : "/*"
case Comments["*/"]:
>Comments["*/"] : typeof Comments["*/"]
>Comments["*/"] : (typeof Comments)["*/"]
>Comments : typeof Comments
>"*/" : "*/"
case Comments["///"]:
>Comments["///"] : typeof Comments["///"]
>Comments["///"] : (typeof Comments)["///"]
>Comments : typeof Comments
>"///" : "///"
case Comments["#"]:
>Comments["#"] : typeof Comments["#"]
>Comments["#"] : (typeof Comments)["#"]
>Comments : typeof Comments
>"#" : "#"
case Comments["<!--"]:
>Comments["<!--"] : typeof Comments["<!--"]
>Comments["<!--"] : (typeof Comments)["<!--"]
>Comments : typeof Comments
>"<!--" : "<!--"
case Comments["-->"]:
>Comments["-->"] : typeof Comments["-->"]
>Comments["-->"] : (typeof Comments)["-->"]
>Comments : typeof Comments
>"-->" : "-->"
@@ -83,7 +83,7 @@ enum e5 {
>"Sunday" : e5.Sunday
"Weekend days"
>"Weekend days" : typeof e5["Weekend days"]
>"Weekend days" : (typeof e5)["Weekend days"]
}
@@ -42,12 +42,12 @@ declare enum AgeGroups {
}
export declare const SpotifyAgeGroupEnum: {
[x: number]: string;
"0-17": typeof AgeGroups["0-17"];
"18-22": typeof AgeGroups["18-22"];
"23-27": typeof AgeGroups["23-27"];
"28-34": typeof AgeGroups["28-34"];
"35-44": typeof AgeGroups["35-44"];
"45-59": typeof AgeGroups["45-59"];
"60-150": typeof AgeGroups["60-150"];
"0-17": (typeof AgeGroups)["0-17"];
"18-22": (typeof AgeGroups)["18-22"];
"23-27": (typeof AgeGroups)["23-27"];
"28-34": (typeof AgeGroups)["28-34"];
"35-44": (typeof AgeGroups)["35-44"];
"45-59": (typeof AgeGroups)["45-59"];
"60-150": (typeof AgeGroups)["60-150"];
};
export {};
@@ -1,16 +1,16 @@
=== tests/cases/compiler/declarationEmitSpreadStringlyKeyedEnum.ts ===
enum AgeGroups { "0-17" , "18-22" , "23-27" , "28-34" , "35-44" , "45-59" , "60-150" }
>AgeGroups : AgeGroups
>"0-17" : typeof AgeGroups["0-17"]
>"18-22" : typeof AgeGroups["18-22"]
>"23-27" : typeof AgeGroups["23-27"]
>"28-34" : typeof AgeGroups["28-34"]
>"35-44" : typeof AgeGroups["35-44"]
>"45-59" : typeof AgeGroups["45-59"]
>"60-150" : typeof AgeGroups["60-150"]
>"0-17" : (typeof AgeGroups)["0-17"]
>"18-22" : (typeof AgeGroups)["18-22"]
>"23-27" : (typeof AgeGroups)["23-27"]
>"28-34" : (typeof AgeGroups)["28-34"]
>"35-44" : (typeof AgeGroups)["35-44"]
>"45-59" : (typeof AgeGroups)["45-59"]
>"60-150" : (typeof AgeGroups)["60-150"]
export const SpotifyAgeGroupEnum = { ...AgeGroups };
>SpotifyAgeGroupEnum : { [x: number]: string; "0-17": typeof AgeGroups["0-17"]; "18-22": typeof AgeGroups["18-22"]; "23-27": typeof AgeGroups["23-27"]; "28-34": typeof AgeGroups["28-34"]; "35-44": typeof AgeGroups["35-44"]; "45-59": typeof AgeGroups["45-59"]; "60-150": typeof AgeGroups["60-150"]; }
>{ ...AgeGroups } : { [x: number]: string; "0-17": typeof AgeGroups["0-17"]; "18-22": typeof AgeGroups["18-22"]; "23-27": typeof AgeGroups["23-27"]; "28-34": typeof AgeGroups["28-34"]; "35-44": typeof AgeGroups["35-44"]; "45-59": typeof AgeGroups["45-59"]; "60-150": typeof AgeGroups["60-150"]; }
>SpotifyAgeGroupEnum : { [x: number]: string; "0-17": (typeof AgeGroups)["0-17"]; "18-22": (typeof AgeGroups)["18-22"]; "23-27": (typeof AgeGroups)["23-27"]; "28-34": (typeof AgeGroups)["28-34"]; "35-44": (typeof AgeGroups)["35-44"]; "45-59": (typeof AgeGroups)["45-59"]; "60-150": (typeof AgeGroups)["60-150"]; }
>{ ...AgeGroups } : { [x: number]: string; "0-17": (typeof AgeGroups)["0-17"]; "18-22": (typeof AgeGroups)["18-22"]; "23-27": (typeof AgeGroups)["23-27"]; "28-34": (typeof AgeGroups)["28-34"]; "35-44": (typeof AgeGroups)["35-44"]; "45-59": (typeof AgeGroups)["45-59"]; "60-150": (typeof AgeGroups)["60-150"]; }
>AgeGroups : typeof AgeGroups
@@ -5,7 +5,7 @@ enum ENUM1 { A, B, "" };
>ENUM1 : ENUM1
>A : ENUM1.A
>B : ENUM1.B
>"" : typeof ENUM1[""]
>"" : (typeof ENUM1)[""]
// expression
var ResultIsNumber1 = --ENUM1["A"];
@@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" };
>ENUM1 : ENUM1
>A : ENUM1.A
>B : ENUM1.B
>"" : typeof ENUM1[""]
>"" : (typeof ENUM1)[""]
// enum type var
var ResultIsNumber1 = --ENUM;
@@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" };
>ENUM1 : ENUM1
>A : ENUM1.A
>B : ENUM1.B
>"" : typeof ENUM1[""]
>"" : (typeof ENUM1)[""]
// enum type var
var ResultIsBoolean1 = delete ENUM;
@@ -7,11 +7,11 @@ enum Foo {
>1 : 1
"(Anonymous function)" = 2,
>"(Anonymous function)" : typeof Foo["(Anonymous function)"]
>"(Anonymous function)" : (typeof Foo)["(Anonymous function)"]
>2 : 2
"(Anonymous class)" = 4,
>"(Anonymous class)" : typeof Foo["(Anonymous class)"]
>"(Anonymous class)" : (typeof Foo)["(Anonymous class)"]
>4 : 4
"__call" = 10
+3 -3
View File
@@ -132,11 +132,11 @@ enum E13 {
postColonValueComma: 2,
>postColonValueComma : E13.postColonValueComma
>2 : typeof E13["2"]
>2 : (typeof E13)["2"]
postColonValueSemicolon: 3;
>postColonValueSemicolon : E13.postColonValueSemicolon
>3 : typeof E13["3"]
>3 : (typeof E13)["3"]
};
@@ -146,7 +146,7 @@ enum E14 { a, b: any "hello" += 1, c, d}
>b : E14.b
>any : E14.any
>"hello" : E14.hello
>1 : typeof E14["1"]
>1 : (typeof E14)["1"]
>c : E14.c
>d : E14.d
@@ -3,17 +3,17 @@ enum Nums {
>Nums : Nums
1.0,
>1.0 : typeof Nums["1"]
>1.0 : (typeof Nums)["1"]
11e-1,
>11e-1 : typeof Nums["1.1"]
>11e-1 : (typeof Nums)["1.1"]
0.12e1,
>0.12e1 : typeof Nums["1.2"]
>0.12e1 : (typeof Nums)["1.2"]
"13e-1",
>"13e-1" : typeof Nums["13e-1"]
>"13e-1" : (typeof Nums)["13e-1"]
0xF00D
>0xF00D : typeof Nums["61453"]
>0xF00D : (typeof Nums)["61453"]
}
@@ -3,7 +3,7 @@ enum A {
>A : A
"-Infinity" = 1
>"-Infinity" : typeof A["-Infinity"]
>"-Infinity" : (typeof A)["-Infinity"]
>1 : 1
}
@@ -3,5 +3,5 @@ enum E {
>E : E
'fo"o',
>'fo"o' : typeof E["fo\"o"]
>'fo"o' : (typeof E)["fo\"o"]
}
@@ -3,5 +3,5 @@ enum E {
>E : E
"fo'o",
>"fo'o" : typeof E["fo'o"]
>"fo'o" : (typeof E)["fo'o"]
}
@@ -3,6 +3,6 @@ enum E {
>E : E
'gold \u2730'
>'gold \u2730' : typeof E["gold \u2730"]
>'gold \u2730' : (typeof E)["gold \u2730"]
}
@@ -5,7 +5,7 @@ enum ENUM1 { A, B, "" };
>ENUM1 : ENUM1
>A : ENUM1.A
>B : ENUM1.B
>"" : typeof ENUM1[""]
>"" : (typeof ENUM1)[""]
// expression
var ResultIsNumber1 = ++ENUM1["B"];
@@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" };
>ENUM1 : ENUM1
>A : ENUM1.A
>B : ENUM1.B
>"" : typeof ENUM1[""]
>"" : (typeof ENUM1)[""]
// enum type var
var ResultIsNumber1 = ++ENUM;
@@ -8,9 +8,9 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(55,25): error TS2344: T
tests/cases/conformance/types/conditional/inferTypes1.ts(56,25): error TS2344: Type 'Function' does not satisfy the constraint '(x: any) => any'.
Type 'Function' provides no match for the signature '(x: any): any'.
tests/cases/conformance/types/conditional/inferTypes1.ts(82,12): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
tests/cases/conformance/types/conditional/inferTypes1.ts(83,15): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
tests/cases/conformance/types/conditional/inferTypes1.ts(83,41): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
tests/cases/conformance/types/conditional/inferTypes1.ts(83,51): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
tests/cases/conformance/types/conditional/inferTypes1.ts(83,16): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
tests/cases/conformance/types/conditional/inferTypes1.ts(83,43): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
tests/cases/conformance/types/conditional/inferTypes1.ts(83,53): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
tests/cases/conformance/types/conditional/inferTypes1.ts(84,15): error TS2304: Cannot find name 'U'.
tests/cases/conformance/types/conditional/inferTypes1.ts(84,15): error TS4081: Exported type alias 'T62' has or is using private name 'U'.
tests/cases/conformance/types/conditional/inferTypes1.ts(84,43): error TS2304: Cannot find name 'U'.
@@ -120,12 +120,12 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(153,40): error TS2322:
type T60 = infer U; // Error
~~~~~~~
!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
type T61<T> = infer A extends infer B ? infer C : infer D; // Error
~~~~~~~
type T61<T> = (infer A) extends infer B ? infer C : infer D; // Error
~~~~~~~
!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
~~~~~~~
~~~~~~~
!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
~~~~~~~
~~~~~~~
!!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
type T62<T> = U extends (infer U)[] ? U : U; // Error
~
@@ -136,7 +136,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(153,40): error TS2322:
!!! error TS2304: Cannot find name 'U'.
~
!!! error TS4081: Exported type alias 'T62' has or is using private name 'U'.
type T63<T> = T extends (infer A extends infer B ? infer C : infer D) ? string : number;
type T63<T> = T extends ((infer A) extends infer B ? infer C : infer D) ? string : number;
type T70<T extends string> = { x: T };
type T71<T> = T extends T70<infer U> ? T70<U> : never;
+2 -2
View File
@@ -81,9 +81,9 @@ type T53 = X3<{ a: (x: number) => void, b: (x: string) => void }>; // never
type T54 = X3<{ a: (x: number) => void, b: () => void }>; // number
type T60 = infer U; // Error
type T61<T> = infer A extends infer B ? infer C : infer D; // Error
type T61<T> = (infer A) extends infer B ? infer C : infer D; // Error
type T62<T> = U extends (infer U)[] ? U : U; // Error
type T63<T> = T extends (infer A extends infer B ? infer C : infer D) ? string : number;
type T63<T> = T extends ((infer A) extends infer B ? infer C : infer D) ? string : number;
type T70<T extends string> = { x: T };
type T71<T> = T extends T70<infer U> ? T70<U> : never;
+16 -16
View File
@@ -349,33 +349,33 @@ type T60 = infer U; // Error
>T60 : Symbol(T60, Decl(inferTypes1.ts, 79, 57))
>U : Symbol(U, Decl(inferTypes1.ts, 81, 16))
type T61<T> = infer A extends infer B ? infer C : infer D; // Error
type T61<T> = (infer A) extends infer B ? infer C : infer D; // Error
>T61 : Symbol(T61, Decl(inferTypes1.ts, 81, 19))
>T : Symbol(T, Decl(inferTypes1.ts, 82, 9))
>A : Symbol(A, Decl(inferTypes1.ts, 82, 19))
>B : Symbol(B, Decl(inferTypes1.ts, 82, 35))
>C : Symbol(C, Decl(inferTypes1.ts, 82, 45))
>D : Symbol(D, Decl(inferTypes1.ts, 82, 55))
>A : Symbol(A, Decl(inferTypes1.ts, 82, 20))
>B : Symbol(B, Decl(inferTypes1.ts, 82, 37))
>C : Symbol(C, Decl(inferTypes1.ts, 82, 47))
>D : Symbol(D, Decl(inferTypes1.ts, 82, 57))
type T62<T> = U extends (infer U)[] ? U : U; // Error
>T62 : Symbol(T62, Decl(inferTypes1.ts, 82, 58))
>T62 : Symbol(T62, Decl(inferTypes1.ts, 82, 60))
>T : Symbol(T, Decl(inferTypes1.ts, 83, 9))
>U : Symbol(U)
>U : Symbol(U, Decl(inferTypes1.ts, 83, 30))
>U : Symbol(U, Decl(inferTypes1.ts, 83, 30))
>U : Symbol(U)
type T63<T> = T extends (infer A extends infer B ? infer C : infer D) ? string : number;
type T63<T> = T extends ((infer A) extends infer B ? infer C : infer D) ? string : number;
>T63 : Symbol(T63, Decl(inferTypes1.ts, 83, 44))
>T : Symbol(T, Decl(inferTypes1.ts, 84, 9))
>T : Symbol(T, Decl(inferTypes1.ts, 84, 9))
>A : Symbol(A, Decl(inferTypes1.ts, 84, 30))
>B : Symbol(B, Decl(inferTypes1.ts, 84, 46))
>C : Symbol(C, Decl(inferTypes1.ts, 84, 56))
>D : Symbol(D, Decl(inferTypes1.ts, 84, 66))
>A : Symbol(A, Decl(inferTypes1.ts, 84, 31))
>B : Symbol(B, Decl(inferTypes1.ts, 84, 48))
>C : Symbol(C, Decl(inferTypes1.ts, 84, 58))
>D : Symbol(D, Decl(inferTypes1.ts, 84, 68))
type T70<T extends string> = { x: T };
>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 88))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 90))
>T : Symbol(T, Decl(inferTypes1.ts, 86, 9))
>x : Symbol(x, Decl(inferTypes1.ts, 86, 30))
>T : Symbol(T, Decl(inferTypes1.ts, 86, 9))
@@ -384,9 +384,9 @@ type T71<T> = T extends T70<infer U> ? T70<U> : never;
>T71 : Symbol(T71, Decl(inferTypes1.ts, 86, 38))
>T : Symbol(T, Decl(inferTypes1.ts, 87, 9))
>T : Symbol(T, Decl(inferTypes1.ts, 87, 9))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 88))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 90))
>U : Symbol(U, Decl(inferTypes1.ts, 87, 33))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 88))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 90))
>U : Symbol(U, Decl(inferTypes1.ts, 87, 33))
type T72<T extends number> = { y: T };
@@ -401,7 +401,7 @@ type T73<T> = T extends T72<infer U> ? T70<U> : never; // Error
>T : Symbol(T, Decl(inferTypes1.ts, 90, 9))
>T72 : Symbol(T72, Decl(inferTypes1.ts, 87, 54))
>U : Symbol(U, Decl(inferTypes1.ts, 90, 33))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 88))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 90))
>U : Symbol(U, Decl(inferTypes1.ts, 90, 33))
type T74<T extends number, U extends string> = { x: T, y: U };
@@ -420,7 +420,7 @@ type T75<T> = T extends T74<infer U, infer U> ? T70<U> | T72<U> | T74<U, U> : ne
>T74 : Symbol(T74, Decl(inferTypes1.ts, 90, 54))
>U : Symbol(U, Decl(inferTypes1.ts, 93, 33), Decl(inferTypes1.ts, 93, 42))
>U : Symbol(U, Decl(inferTypes1.ts, 93, 33), Decl(inferTypes1.ts, 93, 42))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 88))
>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 90))
>U : Symbol(U, Decl(inferTypes1.ts, 93, 33), Decl(inferTypes1.ts, 93, 42))
>T72 : Symbol(T72, Decl(inferTypes1.ts, 87, 54))
>U : Symbol(U, Decl(inferTypes1.ts, 93, 33), Decl(inferTypes1.ts, 93, 42))
+2 -2
View File
@@ -253,13 +253,13 @@ type T54 = X3<{ a: (x: number) => void, b: () => void }>; // number
type T60 = infer U; // Error
>T60 : U
type T61<T> = infer A extends infer B ? infer C : infer D; // Error
type T61<T> = (infer A) extends infer B ? infer C : infer D; // Error
>T61 : T61<T>
type T62<T> = U extends (infer U)[] ? U : U; // Error
>T62 : any
type T63<T> = T extends (infer A extends infer B ? infer C : infer D) ? string : number;
type T63<T> = T extends ((infer A) extends infer B ? infer C : infer D) ? string : number;
>T63 : T63<T>
type T70<T extends string> = { x: T };
@@ -0,0 +1,298 @@
//// [inferTypesWithExtends1.ts]
// infer to tuple element
type X1<T extends any[]> =
T extends [infer U extends string] ? ["string", U] :
T extends [infer U extends number] ? ["number", U] :
never;
type X1_T1 = X1<["a"]>; // ["string", "a"]
type X1_T2 = X1<[1]>; // ["number", 1]
type X1_T3 = X1<[object]>; // never
// infer to argument
type X2<T extends (...args: any[]) => void> =
T extends (a: infer U extends string) => void ? ["string", U] :
T extends (a: infer U extends number) => void ? ["number", U] :
never;
type X2_T1 = X2<(a: "a") => void>; // ["string", "a"]
type X2_T2 = X2<(a: 1) => void>; // ["number", 1]
type X2_T3 = X2<(a: object) => void>; // never
// infer to return type
type X3<T extends (...args: any[]) => any> =
T extends (...args: any[]) => (infer U extends string) ? ["string", U] :
T extends (...args: any[]) => (infer U extends number) ? ["number", U] :
never;
type X3_T1 = X3<() => "a">; // ["string", "a"]
type X3_T2 = X3<() => 1>; // ["number", 1]
type X3_T3 = X3<() => object>; // never
// infer to instance type
type X4<T extends new (...args: any[]) => any> =
T extends new (...args: any[]) => (infer U extends { a: string }) ? ["string", U] :
T extends new (...args: any[]) => (infer U extends { a: number }) ? ["number", U] :
never;
type X4_T1 = X4<new () => { a: "a" }>; // ["string", { a: "a" }]
type X4_T2 = X4<new () => { a: 1 }>; // ["number", { a: 1 }]
type X4_T3 = X4<new () => { a: object }>; // never
// infer to type argument
type X5<T> =
T extends Promise<infer U extends string> ? ["string", U] :
T extends Promise<infer U extends number> ? ["number", U] :
never;
type X5_T1 = X5<Promise<"a" | "b">>; // ["string", "a" | "b"]
type X5_T2 = X5<Promise<1 | 2>>; // ["number", 1 | 2]
type X5_T3 = X5<Promise<1n | 2n>>; // never
// infer to property type
type X6<T> =
T extends { a: infer U extends string } ? ["string", U] :
T extends { a: infer U extends number } ? ["number", U] :
never;
type X6_T1 = X6<{ a: "a" }>; // ["string", "a"]
type X6_T2 = X6<{ a: 1 }>; // ["number", 1]
type X6_T3 = X6<{ a: object }>; // never
// infer twice with same constraint
type X7<T> =
T extends { a: infer U extends string, b: infer U extends string } ? ["string", U] :
T extends { a: infer U extends number, b: infer U extends number } ? ["number", U] :
never;
type X7_T1 = X7<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
type X7_T2 = X7<{ a: 1, b: 2 }>; // ["number", 1 | 2]
type X7_T3 = X7<{ a: object, b: object }>; // never
type X7_T4 = X7<{ a: "a", b: 1 }>; // never
// infer twice with missing second constraint (same behavior as class/interface)
type X8<T> =
T extends { a: infer U extends string, b: infer U } ? ["string", U] :
T extends { a: infer U extends number, b: infer U } ? ["number", U] :
never;
type X8_T1 = X8<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
type X8_T2 = X8<{ a: 1, b: 2 }>; // ["number", 1 | 2]
type X8_T3 = X8<{ a: object, b: object }>; // never
type X8_T4 = X8<{ a: "a", b: 1 }>; // never
// infer twice with missing first constraint (same behavior as class/interface)
type X9<T> =
T extends { a: infer U, b: infer U extends string } ? ["string", U] :
T extends { a: infer U, b: infer U extends number } ? ["number", U] :
never;
type X9_T1 = X9<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
type X9_T2 = X9<{ a: 1, b: 2 }>; // ["number", 1 | 2]
type X9_T3 = X9<{ a: object, b: object }>; // never
type X9_T4 = X9<{ a: "a", b: 1 }>; // never
// Speculative lookahead for `infer T extends U ?`
type X10<T> = T extends (infer U extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional
type X10_Y1<T> = X10<T extends number ? 1 : 0>;
type X10_T1_T1 = X10_Y1<number>;
type X11<T> = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional
type X12<T> = T extends (infer U extends number) ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
type X13<T> = T extends infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (conditional types not allowed in 'extends type')
type X14<T> = T extends keyof infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (precedence wouldn't have parsed the `?` as part of a type operator)
type X15<T> = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional
type X16<T> = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
type X17<T> = T extends { [P in keyof T as infer U extends P ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional
type X18<T> = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
type X19<T extends string | number> = T extends (infer U extends number) ? [T, U] : never;
type X19_T1 = X19<"a">; // never
type X19_T2 = X19<1>; // [1, 1]
type X19_T3 = X19<1 | "a">; // [1, 1]
type X20<T> = T extends (infer U extends number) ? T extends (infer V extends U) ? [T, U, V] : never : never;
type X20_T1 = X20<1 | "a">; // [1, 1, 1]
type X21<T, N extends number> = T extends (infer U extends N) ? [T, U] : never;
type X21_T1 = X21<1, 1>; // [1, 1]
type X21_T2 = X21<1 | "a", 1>; // [1, 1]
type X21_T3 = X21<1 | 2, 1>; // [1, 1]
type X21_T4 = X21<1 | 2, 2 | 3>; // [2, 2]
type X21_T5 = X21<1 | 2, 3>; // never
// from mongoose
type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B;
declare const x1: <T>() => (T extends infer U extends number ? 1 : 0);
function f1() {
return x1;
}
type ExpectNumber<T extends number> = T;
declare const x2: <T>() => (T extends ExpectNumber<infer U> ? 1 : 0);
function f2() {
return x2;
}
//// [inferTypesWithExtends1.js]
"use strict";
function f1() {
return x1;
}
function f2() {
return x2;
}
//// [inferTypesWithExtends1.d.ts]
declare type X1<T extends any[]> = T extends [infer U extends string] ? ["string", U] : T extends [infer U extends number] ? ["number", U] : never;
declare type X1_T1 = X1<["a"]>;
declare type X1_T2 = X1<[1]>;
declare type X1_T3 = X1<[object]>;
declare type X2<T extends (...args: any[]) => void> = T extends (a: infer U extends string) => void ? ["string", U] : T extends (a: infer U extends number) => void ? ["number", U] : never;
declare type X2_T1 = X2<(a: "a") => void>;
declare type X2_T2 = X2<(a: 1) => void>;
declare type X2_T3 = X2<(a: object) => void>;
declare type X3<T extends (...args: any[]) => any> = T extends (...args: any[]) => (infer U extends string) ? ["string", U] : T extends (...args: any[]) => (infer U extends number) ? ["number", U] : never;
declare type X3_T1 = X3<() => "a">;
declare type X3_T2 = X3<() => 1>;
declare type X3_T3 = X3<() => object>;
declare type X4<T extends new (...args: any[]) => any> = T extends new (...args: any[]) => (infer U extends {
a: string;
}) ? ["string", U] : T extends new (...args: any[]) => (infer U extends {
a: number;
}) ? ["number", U] : never;
declare type X4_T1 = X4<new () => {
a: "a";
}>;
declare type X4_T2 = X4<new () => {
a: 1;
}>;
declare type X4_T3 = X4<new () => {
a: object;
}>;
declare type X5<T> = T extends Promise<infer U extends string> ? ["string", U] : T extends Promise<infer U extends number> ? ["number", U] : never;
declare type X5_T1 = X5<Promise<"a" | "b">>;
declare type X5_T2 = X5<Promise<1 | 2>>;
declare type X5_T3 = X5<Promise<1n | 2n>>;
declare type X6<T> = T extends {
a: infer U extends string;
} ? ["string", U] : T extends {
a: infer U extends number;
} ? ["number", U] : never;
declare type X6_T1 = X6<{
a: "a";
}>;
declare type X6_T2 = X6<{
a: 1;
}>;
declare type X6_T3 = X6<{
a: object;
}>;
declare type X7<T> = T extends {
a: infer U extends string;
b: infer U extends string;
} ? ["string", U] : T extends {
a: infer U extends number;
b: infer U extends number;
} ? ["number", U] : never;
declare type X7_T1 = X7<{
a: "a";
b: "b";
}>;
declare type X7_T2 = X7<{
a: 1;
b: 2;
}>;
declare type X7_T3 = X7<{
a: object;
b: object;
}>;
declare type X7_T4 = X7<{
a: "a";
b: 1;
}>;
declare type X8<T> = T extends {
a: infer U extends string;
b: infer U;
} ? ["string", U] : T extends {
a: infer U extends number;
b: infer U;
} ? ["number", U] : never;
declare type X8_T1 = X8<{
a: "a";
b: "b";
}>;
declare type X8_T2 = X8<{
a: 1;
b: 2;
}>;
declare type X8_T3 = X8<{
a: object;
b: object;
}>;
declare type X8_T4 = X8<{
a: "a";
b: 1;
}>;
declare type X9<T> = T extends {
a: infer U;
b: infer U extends string;
} ? ["string", U] : T extends {
a: infer U;
b: infer U extends number;
} ? ["number", U] : never;
declare type X9_T1 = X9<{
a: "a";
b: "b";
}>;
declare type X9_T2 = X9<{
a: 1;
b: 2;
}>;
declare type X9_T3 = X9<{
a: object;
b: object;
}>;
declare type X9_T4 = X9<{
a: "a";
b: 1;
}>;
declare type X10<T> = T extends (infer U extends number ? 1 : 0) ? 1 : 0;
declare type X10_Y1<T> = X10<T extends number ? 1 : 0>;
declare type X10_T1_T1 = X10_Y1<number>;
declare type X11<T> = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0;
declare type X12<T> = T extends (infer U extends number) ? 1 : 0;
declare type X13<T> = T extends infer U extends number ? 1 : 0;
declare type X14<T> = T extends keyof infer U extends number ? 1 : 0;
declare type X15<T> = T extends {
[P in infer U extends keyof T ? 1 : 0]: 1;
} ? 1 : 0;
declare type X16<T> = T extends {
[P in infer U extends keyof T]: 1;
} ? 1 : 0;
declare type X17<T> = T extends {
[P in keyof T as infer U extends P ? 1 : 0]: 1;
} ? 1 : 0;
declare type X18<T> = T extends {
[P in keyof T as infer U extends P]: 1;
} ? 1 : 0;
declare type X19<T extends string | number> = T extends (infer U extends number) ? [T, U] : never;
declare type X19_T1 = X19<"a">;
declare type X19_T2 = X19<1>;
declare type X19_T3 = X19<1 | "a">;
declare type X20<T> = T extends (infer U extends number) ? T extends (infer V extends U) ? [T, U, V] : never : never;
declare type X20_T1 = X20<1 | "a">;
declare type X21<T, N extends number> = T extends (infer U extends N) ? [T, U] : never;
declare type X21_T1 = X21<1, 1>;
declare type X21_T2 = X21<1 | "a", 1>;
declare type X21_T3 = X21<1 | 2, 1>;
declare type X21_T4 = X21<1 | 2, 2 | 3>;
declare type X21_T5 = X21<1 | 2, 3>;
declare type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B;
declare const x1: <T>() => (T extends infer U extends number ? 1 : 0);
declare function f1(): <T>() => T extends infer U extends number ? 1 : 0;
declare type ExpectNumber<T extends number> = T;
declare const x2: <T>() => (T extends ExpectNumber<infer U> ? 1 : 0);
declare function f2(): <T>() => T extends infer U extends number ? 1 : 0;
@@ -0,0 +1,531 @@
=== tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts ===
// infer to tuple element
type X1<T extends any[]> =
>X1 : Symbol(X1, Decl(inferTypesWithExtends1.ts, 0, 0))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 1, 8))
T extends [infer U extends string] ? ["string", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 1, 8))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 2, 20))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 2, 20))
T extends [infer U extends number] ? ["number", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 1, 8))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 3, 20))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 3, 20))
never;
type X1_T1 = X1<["a"]>; // ["string", "a"]
>X1_T1 : Symbol(X1_T1, Decl(inferTypesWithExtends1.ts, 4, 10))
>X1 : Symbol(X1, Decl(inferTypesWithExtends1.ts, 0, 0))
type X1_T2 = X1<[1]>; // ["number", 1]
>X1_T2 : Symbol(X1_T2, Decl(inferTypesWithExtends1.ts, 6, 23))
>X1 : Symbol(X1, Decl(inferTypesWithExtends1.ts, 0, 0))
type X1_T3 = X1<[object]>; // never
>X1_T3 : Symbol(X1_T3, Decl(inferTypesWithExtends1.ts, 7, 21))
>X1 : Symbol(X1, Decl(inferTypesWithExtends1.ts, 0, 0))
// infer to argument
type X2<T extends (...args: any[]) => void> =
>X2 : Symbol(X2, Decl(inferTypesWithExtends1.ts, 8, 26))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 11, 8))
>args : Symbol(args, Decl(inferTypesWithExtends1.ts, 11, 19))
T extends (a: infer U extends string) => void ? ["string", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 11, 8))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 12, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 12, 23))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 12, 23))
T extends (a: infer U extends number) => void ? ["number", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 11, 8))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 13, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 13, 23))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 13, 23))
never;
type X2_T1 = X2<(a: "a") => void>; // ["string", "a"]
>X2_T1 : Symbol(X2_T1, Decl(inferTypesWithExtends1.ts, 14, 10))
>X2 : Symbol(X2, Decl(inferTypesWithExtends1.ts, 8, 26))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 16, 17))
type X2_T2 = X2<(a: 1) => void>; // ["number", 1]
>X2_T2 : Symbol(X2_T2, Decl(inferTypesWithExtends1.ts, 16, 34))
>X2 : Symbol(X2, Decl(inferTypesWithExtends1.ts, 8, 26))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 17, 17))
type X2_T3 = X2<(a: object) => void>; // never
>X2_T3 : Symbol(X2_T3, Decl(inferTypesWithExtends1.ts, 17, 32))
>X2 : Symbol(X2, Decl(inferTypesWithExtends1.ts, 8, 26))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 18, 17))
// infer to return type
type X3<T extends (...args: any[]) => any> =
>X3 : Symbol(X3, Decl(inferTypesWithExtends1.ts, 18, 37))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 21, 8))
>args : Symbol(args, Decl(inferTypesWithExtends1.ts, 21, 19))
T extends (...args: any[]) => (infer U extends string) ? ["string", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 21, 8))
>args : Symbol(args, Decl(inferTypesWithExtends1.ts, 22, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 22, 40))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 22, 40))
T extends (...args: any[]) => (infer U extends number) ? ["number", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 21, 8))
>args : Symbol(args, Decl(inferTypesWithExtends1.ts, 23, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 23, 40))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 23, 40))
never;
type X3_T1 = X3<() => "a">; // ["string", "a"]
>X3_T1 : Symbol(X3_T1, Decl(inferTypesWithExtends1.ts, 24, 10))
>X3 : Symbol(X3, Decl(inferTypesWithExtends1.ts, 18, 37))
type X3_T2 = X3<() => 1>; // ["number", 1]
>X3_T2 : Symbol(X3_T2, Decl(inferTypesWithExtends1.ts, 26, 27))
>X3 : Symbol(X3, Decl(inferTypesWithExtends1.ts, 18, 37))
type X3_T3 = X3<() => object>; // never
>X3_T3 : Symbol(X3_T3, Decl(inferTypesWithExtends1.ts, 27, 25))
>X3 : Symbol(X3, Decl(inferTypesWithExtends1.ts, 18, 37))
// infer to instance type
type X4<T extends new (...args: any[]) => any> =
>X4 : Symbol(X4, Decl(inferTypesWithExtends1.ts, 28, 30))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 31, 8))
>args : Symbol(args, Decl(inferTypesWithExtends1.ts, 31, 23))
T extends new (...args: any[]) => (infer U extends { a: string }) ? ["string", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 31, 8))
>args : Symbol(args, Decl(inferTypesWithExtends1.ts, 32, 19))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 32, 44))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 32, 56))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 32, 44))
T extends new (...args: any[]) => (infer U extends { a: number }) ? ["number", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 31, 8))
>args : Symbol(args, Decl(inferTypesWithExtends1.ts, 33, 19))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 33, 44))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 33, 56))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 33, 44))
never;
type X4_T1 = X4<new () => { a: "a" }>; // ["string", { a: "a" }]
>X4_T1 : Symbol(X4_T1, Decl(inferTypesWithExtends1.ts, 34, 10))
>X4 : Symbol(X4, Decl(inferTypesWithExtends1.ts, 28, 30))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 36, 27))
type X4_T2 = X4<new () => { a: 1 }>; // ["number", { a: 1 }]
>X4_T2 : Symbol(X4_T2, Decl(inferTypesWithExtends1.ts, 36, 38))
>X4 : Symbol(X4, Decl(inferTypesWithExtends1.ts, 28, 30))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 37, 27))
type X4_T3 = X4<new () => { a: object }>; // never
>X4_T3 : Symbol(X4_T3, Decl(inferTypesWithExtends1.ts, 37, 36))
>X4 : Symbol(X4, Decl(inferTypesWithExtends1.ts, 28, 30))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 38, 27))
// infer to type argument
type X5<T> =
>X5 : Symbol(X5, Decl(inferTypesWithExtends1.ts, 38, 41))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 41, 8))
T extends Promise<infer U extends string> ? ["string", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 41, 8))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 42, 27))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 42, 27))
T extends Promise<infer U extends number> ? ["number", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 41, 8))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 43, 27))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 43, 27))
never;
type X5_T1 = X5<Promise<"a" | "b">>; // ["string", "a" | "b"]
>X5_T1 : Symbol(X5_T1, Decl(inferTypesWithExtends1.ts, 44, 10))
>X5 : Symbol(X5, Decl(inferTypesWithExtends1.ts, 38, 41))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
type X5_T2 = X5<Promise<1 | 2>>; // ["number", 1 | 2]
>X5_T2 : Symbol(X5_T2, Decl(inferTypesWithExtends1.ts, 46, 36))
>X5 : Symbol(X5, Decl(inferTypesWithExtends1.ts, 38, 41))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
type X5_T3 = X5<Promise<1n | 2n>>; // never
>X5_T3 : Symbol(X5_T3, Decl(inferTypesWithExtends1.ts, 47, 32))
>X5 : Symbol(X5, Decl(inferTypesWithExtends1.ts, 38, 41))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
// infer to property type
type X6<T> =
>X6 : Symbol(X6, Decl(inferTypesWithExtends1.ts, 48, 34))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 51, 8))
T extends { a: infer U extends string } ? ["string", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 51, 8))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 52, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 52, 24))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 52, 24))
T extends { a: infer U extends number } ? ["number", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 51, 8))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 53, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 53, 24))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 53, 24))
never;
type X6_T1 = X6<{ a: "a" }>; // ["string", "a"]
>X6_T1 : Symbol(X6_T1, Decl(inferTypesWithExtends1.ts, 54, 10))
>X6 : Symbol(X6, Decl(inferTypesWithExtends1.ts, 48, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 56, 17))
type X6_T2 = X6<{ a: 1 }>; // ["number", 1]
>X6_T2 : Symbol(X6_T2, Decl(inferTypesWithExtends1.ts, 56, 28))
>X6 : Symbol(X6, Decl(inferTypesWithExtends1.ts, 48, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 57, 17))
type X6_T3 = X6<{ a: object }>; // never
>X6_T3 : Symbol(X6_T3, Decl(inferTypesWithExtends1.ts, 57, 26))
>X6 : Symbol(X6, Decl(inferTypesWithExtends1.ts, 48, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 58, 17))
// infer twice with same constraint
type X7<T> =
>X7 : Symbol(X7, Decl(inferTypesWithExtends1.ts, 58, 31))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 61, 8))
T extends { a: infer U extends string, b: infer U extends string } ? ["string", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 61, 8))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 62, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 62, 24), Decl(inferTypesWithExtends1.ts, 62, 51))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 62, 42))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 62, 24), Decl(inferTypesWithExtends1.ts, 62, 51))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 62, 24), Decl(inferTypesWithExtends1.ts, 62, 51))
T extends { a: infer U extends number, b: infer U extends number } ? ["number", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 61, 8))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 63, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 63, 24), Decl(inferTypesWithExtends1.ts, 63, 51))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 63, 42))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 63, 24), Decl(inferTypesWithExtends1.ts, 63, 51))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 63, 24), Decl(inferTypesWithExtends1.ts, 63, 51))
never;
type X7_T1 = X7<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
>X7_T1 : Symbol(X7_T1, Decl(inferTypesWithExtends1.ts, 64, 10))
>X7 : Symbol(X7, Decl(inferTypesWithExtends1.ts, 58, 31))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 66, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 66, 25))
type X7_T2 = X7<{ a: 1, b: 2 }>; // ["number", 1 | 2]
>X7_T2 : Symbol(X7_T2, Decl(inferTypesWithExtends1.ts, 66, 36))
>X7 : Symbol(X7, Decl(inferTypesWithExtends1.ts, 58, 31))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 67, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 67, 23))
type X7_T3 = X7<{ a: object, b: object }>; // never
>X7_T3 : Symbol(X7_T3, Decl(inferTypesWithExtends1.ts, 67, 32))
>X7 : Symbol(X7, Decl(inferTypesWithExtends1.ts, 58, 31))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 68, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 68, 28))
type X7_T4 = X7<{ a: "a", b: 1 }>; // never
>X7_T4 : Symbol(X7_T4, Decl(inferTypesWithExtends1.ts, 68, 42))
>X7 : Symbol(X7, Decl(inferTypesWithExtends1.ts, 58, 31))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 69, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 69, 25))
// infer twice with missing second constraint (same behavior as class/interface)
type X8<T> =
>X8 : Symbol(X8, Decl(inferTypesWithExtends1.ts, 69, 34))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 72, 8))
T extends { a: infer U extends string, b: infer U } ? ["string", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 72, 8))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 73, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 73, 24), Decl(inferTypesWithExtends1.ts, 73, 51))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 73, 42))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 73, 24), Decl(inferTypesWithExtends1.ts, 73, 51))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 73, 24), Decl(inferTypesWithExtends1.ts, 73, 51))
T extends { a: infer U extends number, b: infer U } ? ["number", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 72, 8))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 74, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 74, 24), Decl(inferTypesWithExtends1.ts, 74, 51))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 74, 42))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 74, 24), Decl(inferTypesWithExtends1.ts, 74, 51))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 74, 24), Decl(inferTypesWithExtends1.ts, 74, 51))
never;
type X8_T1 = X8<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
>X8_T1 : Symbol(X8_T1, Decl(inferTypesWithExtends1.ts, 75, 10))
>X8 : Symbol(X8, Decl(inferTypesWithExtends1.ts, 69, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 77, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 77, 25))
type X8_T2 = X8<{ a: 1, b: 2 }>; // ["number", 1 | 2]
>X8_T2 : Symbol(X8_T2, Decl(inferTypesWithExtends1.ts, 77, 36))
>X8 : Symbol(X8, Decl(inferTypesWithExtends1.ts, 69, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 78, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 78, 23))
type X8_T3 = X8<{ a: object, b: object }>; // never
>X8_T3 : Symbol(X8_T3, Decl(inferTypesWithExtends1.ts, 78, 32))
>X8 : Symbol(X8, Decl(inferTypesWithExtends1.ts, 69, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 79, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 79, 28))
type X8_T4 = X8<{ a: "a", b: 1 }>; // never
>X8_T4 : Symbol(X8_T4, Decl(inferTypesWithExtends1.ts, 79, 42))
>X8 : Symbol(X8, Decl(inferTypesWithExtends1.ts, 69, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 80, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 80, 25))
// infer twice with missing first constraint (same behavior as class/interface)
type X9<T> =
>X9 : Symbol(X9, Decl(inferTypesWithExtends1.ts, 80, 34))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 83, 8))
T extends { a: infer U, b: infer U extends string } ? ["string", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 83, 8))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 84, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 84, 24), Decl(inferTypesWithExtends1.ts, 84, 36))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 84, 27))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 84, 24), Decl(inferTypesWithExtends1.ts, 84, 36))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 84, 24), Decl(inferTypesWithExtends1.ts, 84, 36))
T extends { a: infer U, b: infer U extends number } ? ["number", U] :
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 83, 8))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 85, 15))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 85, 24), Decl(inferTypesWithExtends1.ts, 85, 36))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 85, 27))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 85, 24), Decl(inferTypesWithExtends1.ts, 85, 36))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 85, 24), Decl(inferTypesWithExtends1.ts, 85, 36))
never;
type X9_T1 = X9<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
>X9_T1 : Symbol(X9_T1, Decl(inferTypesWithExtends1.ts, 86, 10))
>X9 : Symbol(X9, Decl(inferTypesWithExtends1.ts, 80, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 88, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 88, 25))
type X9_T2 = X9<{ a: 1, b: 2 }>; // ["number", 1 | 2]
>X9_T2 : Symbol(X9_T2, Decl(inferTypesWithExtends1.ts, 88, 36))
>X9 : Symbol(X9, Decl(inferTypesWithExtends1.ts, 80, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 89, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 89, 23))
type X9_T3 = X9<{ a: object, b: object }>; // never
>X9_T3 : Symbol(X9_T3, Decl(inferTypesWithExtends1.ts, 89, 32))
>X9 : Symbol(X9, Decl(inferTypesWithExtends1.ts, 80, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 90, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 90, 28))
type X9_T4 = X9<{ a: "a", b: 1 }>; // never
>X9_T4 : Symbol(X9_T4, Decl(inferTypesWithExtends1.ts, 90, 42))
>X9 : Symbol(X9, Decl(inferTypesWithExtends1.ts, 80, 34))
>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 91, 17))
>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 91, 25))
// Speculative lookahead for `infer T extends U ?`
type X10<T> = T extends (infer U extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional
>X10 : Symbol(X10, Decl(inferTypesWithExtends1.ts, 91, 34))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 94, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 94, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 94, 30))
type X10_Y1<T> = X10<T extends number ? 1 : 0>;
>X10_Y1 : Symbol(X10_Y1, Decl(inferTypesWithExtends1.ts, 94, 65))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 95, 12))
>X10 : Symbol(X10, Decl(inferTypesWithExtends1.ts, 91, 34))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 95, 12))
type X10_T1_T1 = X10_Y1<number>;
>X10_T1_T1 : Symbol(X10_T1_T1, Decl(inferTypesWithExtends1.ts, 95, 47))
>X10_Y1 : Symbol(X10_Y1, Decl(inferTypesWithExtends1.ts, 94, 65))
type X11<T> = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional
>X11 : Symbol(X11, Decl(inferTypesWithExtends1.ts, 96, 32))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 98, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 98, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 98, 31))
type X12<T> = T extends (infer U extends number) ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
>X12 : Symbol(X12, Decl(inferTypesWithExtends1.ts, 98, 67))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 99, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 99, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 99, 30))
type X13<T> = T extends infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (conditional types not allowed in 'extends type')
>X13 : Symbol(X13, Decl(inferTypesWithExtends1.ts, 99, 57))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 100, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 100, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 100, 29))
type X14<T> = T extends keyof infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (precedence wouldn't have parsed the `?` as part of a type operator)
>X14 : Symbol(X14, Decl(inferTypesWithExtends1.ts, 100, 55))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 101, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 101, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 101, 35))
type X15<T> = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional
>X15 : Symbol(X15, Decl(inferTypesWithExtends1.ts, 101, 61))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 102, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 102, 9))
>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 102, 27))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 102, 37))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 102, 9))
type X16<T> = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
>X16 : Symbol(X16, Decl(inferTypesWithExtends1.ts, 102, 79))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 103, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 103, 9))
>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 103, 27))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 103, 37))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 103, 9))
type X17<T> = T extends { [P in keyof T as infer U extends P ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional
>X17 : Symbol(X17, Decl(inferTypesWithExtends1.ts, 103, 71))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 104, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 104, 9))
>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 104, 27))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 104, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 104, 48))
>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 104, 27))
type X18<T> = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
>X18 : Symbol(X18, Decl(inferTypesWithExtends1.ts, 104, 84))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 105, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 105, 9))
>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 105, 27))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 105, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 105, 48))
>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 105, 27))
type X19<T extends string | number> = T extends (infer U extends number) ? [T, U] : never;
>X19 : Symbol(X19, Decl(inferTypesWithExtends1.ts, 105, 76))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 107, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 107, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 107, 54))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 107, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 107, 54))
type X19_T1 = X19<"a">; // never
>X19_T1 : Symbol(X19_T1, Decl(inferTypesWithExtends1.ts, 107, 90))
>X19 : Symbol(X19, Decl(inferTypesWithExtends1.ts, 105, 76))
type X19_T2 = X19<1>; // [1, 1]
>X19_T2 : Symbol(X19_T2, Decl(inferTypesWithExtends1.ts, 108, 23))
>X19 : Symbol(X19, Decl(inferTypesWithExtends1.ts, 105, 76))
type X19_T3 = X19<1 | "a">; // [1, 1]
>X19_T3 : Symbol(X19_T3, Decl(inferTypesWithExtends1.ts, 109, 21))
>X19 : Symbol(X19, Decl(inferTypesWithExtends1.ts, 105, 76))
type X20<T> = T extends (infer U extends number) ? T extends (infer V extends U) ? [T, U, V] : never : never;
>X20 : Symbol(X20, Decl(inferTypesWithExtends1.ts, 110, 27))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 112, 9))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 112, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 112, 30))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 112, 9))
>V : Symbol(V, Decl(inferTypesWithExtends1.ts, 112, 67))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 112, 30))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 112, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 112, 30))
>V : Symbol(V, Decl(inferTypesWithExtends1.ts, 112, 67))
type X20_T1 = X20<1 | "a">; // [1, 1, 1]
>X20_T1 : Symbol(X20_T1, Decl(inferTypesWithExtends1.ts, 112, 109))
>X20 : Symbol(X20, Decl(inferTypesWithExtends1.ts, 110, 27))
type X21<T, N extends number> = T extends (infer U extends N) ? [T, U] : never;
>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 115, 9))
>N : Symbol(N, Decl(inferTypesWithExtends1.ts, 115, 11))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 115, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 115, 48))
>N : Symbol(N, Decl(inferTypesWithExtends1.ts, 115, 11))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 115, 9))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 115, 48))
type X21_T1 = X21<1, 1>; // [1, 1]
>X21_T1 : Symbol(X21_T1, Decl(inferTypesWithExtends1.ts, 115, 79))
>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27))
type X21_T2 = X21<1 | "a", 1>; // [1, 1]
>X21_T2 : Symbol(X21_T2, Decl(inferTypesWithExtends1.ts, 116, 24))
>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27))
type X21_T3 = X21<1 | 2, 1>; // [1, 1]
>X21_T3 : Symbol(X21_T3, Decl(inferTypesWithExtends1.ts, 117, 30))
>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27))
type X21_T4 = X21<1 | 2, 2 | 3>; // [2, 2]
>X21_T4 : Symbol(X21_T4, Decl(inferTypesWithExtends1.ts, 118, 28))
>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27))
type X21_T5 = X21<1 | 2, 3>; // never
>X21_T5 : Symbol(X21_T5, Decl(inferTypesWithExtends1.ts, 119, 32))
>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27))
// from mongoose
type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B;
>IfEquals : Symbol(IfEquals, Decl(inferTypesWithExtends1.ts, 120, 28))
>X : Symbol(X, Decl(inferTypesWithExtends1.ts, 123, 14))
>Y : Symbol(Y, Decl(inferTypesWithExtends1.ts, 123, 16))
>A : Symbol(A, Decl(inferTypesWithExtends1.ts, 123, 19))
>B : Symbol(B, Decl(inferTypesWithExtends1.ts, 123, 22))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 123, 30))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 123, 30))
>X : Symbol(X, Decl(inferTypesWithExtends1.ts, 123, 14))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 123, 68))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 123, 68))
>Y : Symbol(Y, Decl(inferTypesWithExtends1.ts, 123, 16))
>A : Symbol(A, Decl(inferTypesWithExtends1.ts, 123, 19))
>B : Symbol(B, Decl(inferTypesWithExtends1.ts, 123, 22))
declare const x1: <T>() => (T extends infer U extends number ? 1 : 0);
>x1 : Symbol(x1, Decl(inferTypesWithExtends1.ts, 125, 13))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 125, 19))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 125, 19))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 125, 43))
function f1() {
>f1 : Symbol(f1, Decl(inferTypesWithExtends1.ts, 125, 70))
return x1;
>x1 : Symbol(x1, Decl(inferTypesWithExtends1.ts, 125, 13))
}
type ExpectNumber<T extends number> = T;
>ExpectNumber : Symbol(ExpectNumber, Decl(inferTypesWithExtends1.ts, 128, 1))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 130, 18))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 130, 18))
declare const x2: <T>() => (T extends ExpectNumber<infer U> ? 1 : 0);
>x2 : Symbol(x2, Decl(inferTypesWithExtends1.ts, 131, 13))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 131, 19))
>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 131, 19))
>ExpectNumber : Symbol(ExpectNumber, Decl(inferTypesWithExtends1.ts, 128, 1))
>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 131, 56))
function f2() {
>f2 : Symbol(f2, Decl(inferTypesWithExtends1.ts, 131, 69))
return x2;
>x2 : Symbol(x2, Decl(inferTypesWithExtends1.ts, 131, 13))
}
@@ -0,0 +1,331 @@
=== tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts ===
// infer to tuple element
type X1<T extends any[]> =
>X1 : X1<T>
T extends [infer U extends string] ? ["string", U] :
T extends [infer U extends number] ? ["number", U] :
never;
type X1_T1 = X1<["a"]>; // ["string", "a"]
>X1_T1 : ["string", "a"]
type X1_T2 = X1<[1]>; // ["number", 1]
>X1_T2 : ["number", 1]
type X1_T3 = X1<[object]>; // never
>X1_T3 : never
// infer to argument
type X2<T extends (...args: any[]) => void> =
>X2 : X2<T>
>args : any[]
T extends (a: infer U extends string) => void ? ["string", U] :
>a : U
T extends (a: infer U extends number) => void ? ["number", U] :
>a : U
never;
type X2_T1 = X2<(a: "a") => void>; // ["string", "a"]
>X2_T1 : ["string", "a"]
>a : "a"
type X2_T2 = X2<(a: 1) => void>; // ["number", 1]
>X2_T2 : ["number", 1]
>a : 1
type X2_T3 = X2<(a: object) => void>; // never
>X2_T3 : never
>a : object
// infer to return type
type X3<T extends (...args: any[]) => any> =
>X3 : X3<T>
>args : any[]
T extends (...args: any[]) => (infer U extends string) ? ["string", U] :
>args : any[]
T extends (...args: any[]) => (infer U extends number) ? ["number", U] :
>args : any[]
never;
type X3_T1 = X3<() => "a">; // ["string", "a"]
>X3_T1 : ["string", "a"]
type X3_T2 = X3<() => 1>; // ["number", 1]
>X3_T2 : ["number", 1]
type X3_T3 = X3<() => object>; // never
>X3_T3 : never
// infer to instance type
type X4<T extends new (...args: any[]) => any> =
>X4 : X4<T>
>args : any[]
T extends new (...args: any[]) => (infer U extends { a: string }) ? ["string", U] :
>args : any[]
>a : string
T extends new (...args: any[]) => (infer U extends { a: number }) ? ["number", U] :
>args : any[]
>a : number
never;
type X4_T1 = X4<new () => { a: "a" }>; // ["string", { a: "a" }]
>X4_T1 : ["string", { a: "a"; }]
>a : "a"
type X4_T2 = X4<new () => { a: 1 }>; // ["number", { a: 1 }]
>X4_T2 : ["number", { a: 1; }]
>a : 1
type X4_T3 = X4<new () => { a: object }>; // never
>X4_T3 : never
>a : object
// infer to type argument
type X5<T> =
>X5 : X5<T>
T extends Promise<infer U extends string> ? ["string", U] :
T extends Promise<infer U extends number> ? ["number", U] :
never;
type X5_T1 = X5<Promise<"a" | "b">>; // ["string", "a" | "b"]
>X5_T1 : ["string", "a" | "b"]
type X5_T2 = X5<Promise<1 | 2>>; // ["number", 1 | 2]
>X5_T2 : ["number", 1 | 2]
type X5_T3 = X5<Promise<1n | 2n>>; // never
>X5_T3 : never
// infer to property type
type X6<T> =
>X6 : X6<T>
T extends { a: infer U extends string } ? ["string", U] :
>a : U
T extends { a: infer U extends number } ? ["number", U] :
>a : U
never;
type X6_T1 = X6<{ a: "a" }>; // ["string", "a"]
>X6_T1 : ["string", "a"]
>a : "a"
type X6_T2 = X6<{ a: 1 }>; // ["number", 1]
>X6_T2 : ["number", 1]
>a : 1
type X6_T3 = X6<{ a: object }>; // never
>X6_T3 : never
>a : object
// infer twice with same constraint
type X7<T> =
>X7 : X7<T>
T extends { a: infer U extends string, b: infer U extends string } ? ["string", U] :
>a : U
>b : U
T extends { a: infer U extends number, b: infer U extends number } ? ["number", U] :
>a : U
>b : U
never;
type X7_T1 = X7<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
>X7_T1 : ["string", "a" | "b"]
>a : "a"
>b : "b"
type X7_T2 = X7<{ a: 1, b: 2 }>; // ["number", 1 | 2]
>X7_T2 : ["number", 1 | 2]
>a : 1
>b : 2
type X7_T3 = X7<{ a: object, b: object }>; // never
>X7_T3 : never
>a : object
>b : object
type X7_T4 = X7<{ a: "a", b: 1 }>; // never
>X7_T4 : never
>a : "a"
>b : 1
// infer twice with missing second constraint (same behavior as class/interface)
type X8<T> =
>X8 : X8<T>
T extends { a: infer U extends string, b: infer U } ? ["string", U] :
>a : U
>b : U
T extends { a: infer U extends number, b: infer U } ? ["number", U] :
>a : U
>b : U
never;
type X8_T1 = X8<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
>X8_T1 : ["string", "a" | "b"]
>a : "a"
>b : "b"
type X8_T2 = X8<{ a: 1, b: 2 }>; // ["number", 1 | 2]
>X8_T2 : ["number", 1 | 2]
>a : 1
>b : 2
type X8_T3 = X8<{ a: object, b: object }>; // never
>X8_T3 : never
>a : object
>b : object
type X8_T4 = X8<{ a: "a", b: 1 }>; // never
>X8_T4 : never
>a : "a"
>b : 1
// infer twice with missing first constraint (same behavior as class/interface)
type X9<T> =
>X9 : X9<T>
T extends { a: infer U, b: infer U extends string } ? ["string", U] :
>a : U
>b : U
T extends { a: infer U, b: infer U extends number } ? ["number", U] :
>a : U
>b : U
never;
type X9_T1 = X9<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
>X9_T1 : ["string", "a" | "b"]
>a : "a"
>b : "b"
type X9_T2 = X9<{ a: 1, b: 2 }>; // ["number", 1 | 2]
>X9_T2 : ["number", 1 | 2]
>a : 1
>b : 2
type X9_T3 = X9<{ a: object, b: object }>; // never
>X9_T3 : never
>a : object
>b : object
type X9_T4 = X9<{ a: "a", b: 1 }>; // never
>X9_T4 : never
>a : "a"
>b : 1
// Speculative lookahead for `infer T extends U ?`
type X10<T> = T extends (infer U extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional
>X10 : X10<T>
type X10_Y1<T> = X10<T extends number ? 1 : 0>;
>X10_Y1 : X10_Y1<T>
type X10_T1_T1 = X10_Y1<number>;
>X10_T1_T1 : 0
type X11<T> = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional
>X11 : X11<T>
type X12<T> = T extends (infer U extends number) ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
>X12 : X12<T>
type X13<T> = T extends infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (conditional types not allowed in 'extends type')
>X13 : X13<T>
type X14<T> = T extends keyof infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (precedence wouldn't have parsed the `?` as part of a type operator)
>X14 : X14<T>
type X15<T> = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional
>X15 : X15<T>
type X16<T> = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
>X16 : X16<T>
type X17<T> = T extends { [P in keyof T as infer U extends P ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional
>X17 : X17<T>
type X18<T> = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
>X18 : X18<T>
type X19<T extends string | number> = T extends (infer U extends number) ? [T, U] : never;
>X19 : X19<T>
type X19_T1 = X19<"a">; // never
>X19_T1 : never
type X19_T2 = X19<1>; // [1, 1]
>X19_T2 : [1, 1]
type X19_T3 = X19<1 | "a">; // [1, 1]
>X19_T3 : [1, 1]
type X20<T> = T extends (infer U extends number) ? T extends (infer V extends U) ? [T, U, V] : never : never;
>X20 : X20<T>
type X20_T1 = X20<1 | "a">; // [1, 1, 1]
>X20_T1 : [1, 1, 1]
type X21<T, N extends number> = T extends (infer U extends N) ? [T, U] : never;
>X21 : X21<T, N>
type X21_T1 = X21<1, 1>; // [1, 1]
>X21_T1 : [1, 1]
type X21_T2 = X21<1 | "a", 1>; // [1, 1]
>X21_T2 : [1, 1]
type X21_T3 = X21<1 | 2, 1>; // [1, 1]
>X21_T3 : [1, 1]
type X21_T4 = X21<1 | 2, 2 | 3>; // [2, 2]
>X21_T4 : [2, 2]
type X21_T5 = X21<1 | 2, 3>; // never
>X21_T5 : never
// from mongoose
type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B;
>IfEquals : IfEquals<X, Y, A, B>
declare const x1: <T>() => (T extends infer U extends number ? 1 : 0);
>x1 : <T>() => T extends infer U extends number ? 1 : 0
function f1() {
>f1 : () => <T>() => T extends infer U extends number ? 1 : 0
return x1;
>x1 : <T>() => T extends infer U extends number ? 1 : 0
}
type ExpectNumber<T extends number> = T;
>ExpectNumber : T
declare const x2: <T>() => (T extends ExpectNumber<infer U> ? 1 : 0);
>x2 : <T>() => T extends infer U extends number ? 1 : 0
function f2() {
>f2 : () => <T>() => T extends infer U extends number ? 1 : 0
return x2;
>x2 : <T>() => T extends infer U extends number ? 1 : 0
}
@@ -0,0 +1,21 @@
tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts(3,26): error TS2838: All declarations of 'U' must have identical constraints.
tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts(3,53): error TS2838: All declarations of 'U' must have identical constraints.
tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts(8,48): error TS2304: Cannot find name 'U'.
==== tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts (3 errors) ====
// infer twice with different constraints (same behavior as class/interface)
type X1<T> =
T extends { a: infer U extends string, b: infer U extends number } ? U :
~
!!! error TS2838: All declarations of 'U' must have identical constraints.
~
!!! error TS2838: All declarations of 'U' must have identical constraints.
never;
// infer cannot reference type params in same 'extends' clause
type X2<T> =
T extends { a: infer U, b: infer V extends U } ? [U, V] :
~
!!! error TS2304: Cannot find name 'U'.
never;
@@ -0,0 +1,13 @@
//// [inferTypesWithExtends2.ts]
// infer twice with different constraints (same behavior as class/interface)
type X1<T> =
T extends { a: infer U extends string, b: infer U extends number } ? U :
never;
// infer cannot reference type params in same 'extends' clause
type X2<T> =
T extends { a: infer U, b: infer V extends U } ? [U, V] :
never;
//// [inferTypesWithExtends2.js]
"use strict";
@@ -0,0 +1,32 @@
=== tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts ===
// infer twice with different constraints (same behavior as class/interface)
type X1<T> =
>X1 : Symbol(X1, Decl(inferTypesWithExtends2.ts, 0, 0))
>T : Symbol(T, Decl(inferTypesWithExtends2.ts, 1, 8))
T extends { a: infer U extends string, b: infer U extends number } ? U :
>T : Symbol(T, Decl(inferTypesWithExtends2.ts, 1, 8))
>a : Symbol(a, Decl(inferTypesWithExtends2.ts, 2, 15))
>U : Symbol(U, Decl(inferTypesWithExtends2.ts, 2, 24), Decl(inferTypesWithExtends2.ts, 2, 51))
>b : Symbol(b, Decl(inferTypesWithExtends2.ts, 2, 42))
>U : Symbol(U, Decl(inferTypesWithExtends2.ts, 2, 24), Decl(inferTypesWithExtends2.ts, 2, 51))
>U : Symbol(U, Decl(inferTypesWithExtends2.ts, 2, 24), Decl(inferTypesWithExtends2.ts, 2, 51))
never;
// infer cannot reference type params in same 'extends' clause
type X2<T> =
>X2 : Symbol(X2, Decl(inferTypesWithExtends2.ts, 3, 10))
>T : Symbol(T, Decl(inferTypesWithExtends2.ts, 6, 8))
T extends { a: infer U, b: infer V extends U } ? [U, V] :
>T : Symbol(T, Decl(inferTypesWithExtends2.ts, 6, 8))
>a : Symbol(a, Decl(inferTypesWithExtends2.ts, 7, 15))
>U : Symbol(U, Decl(inferTypesWithExtends2.ts, 7, 24))
>b : Symbol(b, Decl(inferTypesWithExtends2.ts, 7, 27))
>V : Symbol(V, Decl(inferTypesWithExtends2.ts, 7, 36))
>U : Symbol(U)
>U : Symbol(U, Decl(inferTypesWithExtends2.ts, 7, 24))
>V : Symbol(V, Decl(inferTypesWithExtends2.ts, 7, 36))
never;
@@ -0,0 +1,20 @@
=== tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts ===
// infer twice with different constraints (same behavior as class/interface)
type X1<T> =
>X1 : X1<T>
T extends { a: infer U extends string, b: infer U extends number } ? U :
>a : U
>b : U
never;
// infer cannot reference type params in same 'extends' clause
type X2<T> =
>X2 : X2<T>
T extends { a: infer U, b: infer V extends U } ? [U, V] :
>a : U
>b : V
never;
@@ -15,7 +15,7 @@ type AProp<T extends { a: string }> = T
>a : string
declare function myBug<
>myBug : <T extends { [K in keyof T]: T[K] extends infer U ? U : never; }>(arg: T) => T
>myBug : <T extends { [K in keyof T]: T[K] extends infer U extends { a: string; } ? U : never; }>(arg: T) => T
T extends { [K in keyof T]: T[K] extends AProp<infer U> ? U : never }
>(arg: T): T
@@ -24,7 +24,7 @@ declare function myBug<
const out = myBug({obj1: {a: "test"}})
>out : { obj1: { a: string; }; }
>myBug({obj1: {a: "test"}}) : { obj1: { a: string; }; }
>myBug : <T extends { [K in keyof T]: T[K] extends infer U ? U : never; }>(arg: T) => T
>myBug : <T extends { [K in keyof T]: T[K] extends infer U extends { a: string; } ? U : never; }>(arg: T) => T
>{obj1: {a: "test"}} : { obj1: { a: string; }; }
>obj1 : { a: string; }
>{a: "test"} : { a: string; }
@@ -495,7 +495,7 @@ function fn4<K extends number>() {
>'abc' : "abc"
let y: ReadonlyArray<string>[K] = 'abc';
>y : readonly string[][K]
>y : (readonly string[])[K]
>'abc' : "abc"
}
@@ -161,20 +161,20 @@ enum X {
>X : X
1 = 1,
>1 : typeof X["1"]
>1 : (typeof X)["1"]
>1 : 1
[2] = 2,
>[2] : typeof X["2"]
>[2] : (typeof X)["2"]
>2 : 2
>2 : 2
"3" = 3,
>"3" : typeof X["3"]
>"3" : (typeof X)["3"]
>3 : 3
["4"] = 4,
>["4"] : typeof X["4"]
>["4"] : (typeof X)["4"]
>"4" : "4"
>4 : 4
@@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" };
>ENUM1 : ENUM1
>A : ENUM1.A
>B : ENUM1.B
>"" : typeof ENUM1[""]
>"" : (typeof ENUM1)[""]
// enum type var
var ResultIsNumber1 = -ENUM;
@@ -32,7 +32,7 @@ var ResultIsNumber3 = -(ENUM1.B + ENUM1[""]);
>ENUM1.B : ENUM1.B
>ENUM1 : typeof ENUM1
>B : ENUM1.B
>ENUM1[""] : typeof ENUM1[""]
>ENUM1[""] : (typeof ENUM1)[""]
>ENUM1 : typeof ENUM1
>"" : ""
+2 -2
View File
@@ -6,13 +6,13 @@ enum E2 { a, }
enum E3 { a: 1, }
>E3 : E3
>a : E3.a
>1 : typeof E3["1"]
>1 : (typeof E3)["1"]
enum E1 { a, b: 1, c, d: 2 = 3 }
>E1 : E1
>a : E1.a
>b : E1.b
>1 : typeof E1["1"]
>1 : (typeof E1)["1"]
>c : E1.c
>d : E1.d
>2 : E1.c
+3 -3
View File
@@ -3,7 +3,7 @@ enum E {
>E : E
1, 2, 3
>1 : typeof E["1"]
>2 : typeof E["2"]
>3 : typeof E["3"]
>1 : (typeof E)["1"]
>2 : (typeof E)["2"]
>3 : (typeof E)["3"]
}
@@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" };
>ENUM1 : ENUM1
>A : ENUM1.A
>B : ENUM1.B
>"" : typeof ENUM1[""]
>"" : (typeof ENUM1)[""]
// enum type var
var ResultIsNumber1 = +ENUM;
@@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" };
>ENUM1 : ENUM1
>A : ENUM1.A
>B : ENUM1.B
>"" : typeof ENUM1[""]
>"" : (typeof ENUM1)[""]
// enum type var
var ResultIsString1 = typeof ENUM;
@@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" };
>ENUM1 : ENUM1
>A : ENUM1.A
>B : ENUM1.B
>"" : typeof ENUM1[""]
>"" : (typeof ENUM1)[""]
// enum type var
var ResultIsAny1 = void ENUM;
@@ -83,9 +83,9 @@ type T53 = X3<{ a: (x: number) => void, b: (x: string) => void }>; // never
type T54 = X3<{ a: (x: number) => void, b: () => void }>; // number
type T60 = infer U; // Error
type T61<T> = infer A extends infer B ? infer C : infer D; // Error
type T61<T> = (infer A) extends infer B ? infer C : infer D; // Error
type T62<T> = U extends (infer U)[] ? U : U; // Error
type T63<T> = T extends (infer A extends infer B ? infer C : infer D) ? string : number;
type T63<T> = T extends ((infer A) extends infer B ? infer C : infer D) ? string : number;
type T70<T extends string> = { x: T };
type T71<T> = T extends T70<infer U> ? T70<U> : never;
@@ -0,0 +1,138 @@
// @strict: true
// @declaration: true
// infer to tuple element
type X1<T extends any[]> =
T extends [infer U extends string] ? ["string", U] :
T extends [infer U extends number] ? ["number", U] :
never;
type X1_T1 = X1<["a"]>; // ["string", "a"]
type X1_T2 = X1<[1]>; // ["number", 1]
type X1_T3 = X1<[object]>; // never
// infer to argument
type X2<T extends (...args: any[]) => void> =
T extends (a: infer U extends string) => void ? ["string", U] :
T extends (a: infer U extends number) => void ? ["number", U] :
never;
type X2_T1 = X2<(a: "a") => void>; // ["string", "a"]
type X2_T2 = X2<(a: 1) => void>; // ["number", 1]
type X2_T3 = X2<(a: object) => void>; // never
// infer to return type
type X3<T extends (...args: any[]) => any> =
T extends (...args: any[]) => (infer U extends string) ? ["string", U] :
T extends (...args: any[]) => (infer U extends number) ? ["number", U] :
never;
type X3_T1 = X3<() => "a">; // ["string", "a"]
type X3_T2 = X3<() => 1>; // ["number", 1]
type X3_T3 = X3<() => object>; // never
// infer to instance type
type X4<T extends new (...args: any[]) => any> =
T extends new (...args: any[]) => (infer U extends { a: string }) ? ["string", U] :
T extends new (...args: any[]) => (infer U extends { a: number }) ? ["number", U] :
never;
type X4_T1 = X4<new () => { a: "a" }>; // ["string", { a: "a" }]
type X4_T2 = X4<new () => { a: 1 }>; // ["number", { a: 1 }]
type X4_T3 = X4<new () => { a: object }>; // never
// infer to type argument
type X5<T> =
T extends Promise<infer U extends string> ? ["string", U] :
T extends Promise<infer U extends number> ? ["number", U] :
never;
type X5_T1 = X5<Promise<"a" | "b">>; // ["string", "a" | "b"]
type X5_T2 = X5<Promise<1 | 2>>; // ["number", 1 | 2]
type X5_T3 = X5<Promise<1n | 2n>>; // never
// infer to property type
type X6<T> =
T extends { a: infer U extends string } ? ["string", U] :
T extends { a: infer U extends number } ? ["number", U] :
never;
type X6_T1 = X6<{ a: "a" }>; // ["string", "a"]
type X6_T2 = X6<{ a: 1 }>; // ["number", 1]
type X6_T3 = X6<{ a: object }>; // never
// infer twice with same constraint
type X7<T> =
T extends { a: infer U extends string, b: infer U extends string } ? ["string", U] :
T extends { a: infer U extends number, b: infer U extends number } ? ["number", U] :
never;
type X7_T1 = X7<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
type X7_T2 = X7<{ a: 1, b: 2 }>; // ["number", 1 | 2]
type X7_T3 = X7<{ a: object, b: object }>; // never
type X7_T4 = X7<{ a: "a", b: 1 }>; // never
// infer twice with missing second constraint (same behavior as class/interface)
type X8<T> =
T extends { a: infer U extends string, b: infer U } ? ["string", U] :
T extends { a: infer U extends number, b: infer U } ? ["number", U] :
never;
type X8_T1 = X8<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
type X8_T2 = X8<{ a: 1, b: 2 }>; // ["number", 1 | 2]
type X8_T3 = X8<{ a: object, b: object }>; // never
type X8_T4 = X8<{ a: "a", b: 1 }>; // never
// infer twice with missing first constraint (same behavior as class/interface)
type X9<T> =
T extends { a: infer U, b: infer U extends string } ? ["string", U] :
T extends { a: infer U, b: infer U extends number } ? ["number", U] :
never;
type X9_T1 = X9<{ a: "a", b: "b" }>; // ["string", "a" | "b"]
type X9_T2 = X9<{ a: 1, b: 2 }>; // ["number", 1 | 2]
type X9_T3 = X9<{ a: object, b: object }>; // never
type X9_T4 = X9<{ a: "a", b: 1 }>; // never
// Speculative lookahead for `infer T extends U ?`
type X10<T> = T extends (infer U extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional
type X10_Y1<T> = X10<T extends number ? 1 : 0>;
type X10_T1_T1 = X10_Y1<number>;
type X11<T> = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional
type X12<T> = T extends (infer U extends number) ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
type X13<T> = T extends infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (conditional types not allowed in 'extends type')
type X14<T> = T extends keyof infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (precedence wouldn't have parsed the `?` as part of a type operator)
type X15<T> = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional
type X16<T> = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
type X17<T> = T extends { [P in keyof T as infer U extends P ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional
type X18<T> = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
type X19<T extends string | number> = T extends (infer U extends number) ? [T, U] : never;
type X19_T1 = X19<"a">; // never
type X19_T2 = X19<1>; // [1, 1]
type X19_T3 = X19<1 | "a">; // [1, 1]
type X20<T> = T extends (infer U extends number) ? T extends (infer V extends U) ? [T, U, V] : never : never;
type X20_T1 = X20<1 | "a">; // [1, 1, 1]
type X21<T, N extends number> = T extends (infer U extends N) ? [T, U] : never;
type X21_T1 = X21<1, 1>; // [1, 1]
type X21_T2 = X21<1 | "a", 1>; // [1, 1]
type X21_T3 = X21<1 | 2, 1>; // [1, 1]
type X21_T4 = X21<1 | 2, 2 | 3>; // [2, 2]
type X21_T5 = X21<1 | 2, 3>; // never
// from mongoose
type IfEquals<X, Y, A, B> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B;
declare const x1: <T>() => (T extends infer U extends number ? 1 : 0);
function f1() {
return x1;
}
type ExpectNumber<T extends number> = T;
declare const x2: <T>() => (T extends ExpectNumber<infer U> ? 1 : 0);
function f2() {
return x2;
}
@@ -0,0 +1,11 @@
// @strict: true
// infer twice with different constraints (same behavior as class/interface)
type X1<T> =
T extends { a: infer U extends string, b: infer U extends number } ? U :
never;
// infer cannot reference type params in same 'extends' clause
type X2<T> =
T extends { a: infer U, b: infer V extends U } ? [U, V] :
never;
@@ -1,13 +1,13 @@
/// <reference path='fourslash.ts' />
//// type Crazy<T> = /*a*/T extends [infer P, (infer R extends string ? string : never)] ? P & R : string/*b*/;
//// type Crazy<T> = /*a*/T extends [infer P, ((infer R) extends string ? string : never)] ? P & R : string/*b*/;
goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Extract type",
actionName: "Extract to type alias",
actionDescription: "Extract to type alias",
newContent: `type /*RENAME*/NewType<T> = T extends [infer P, (infer R extends string ? string : never)] ? P & R : string;
newContent: `type /*RENAME*/NewType<T> = T extends [infer P, ((infer R) extends string ? string : never)] ? P & R : string;
type Crazy<T> = NewType<T>;`,
});