Skip to content

Commit

Permalink
[ts 4.7] Support extends constraints for infer (#14476)
Browse files Browse the repository at this point in the history
  • Loading branch information
sosukesuzuki committed May 17, 2022
1 parent d6ff919 commit 59d24a4
Show file tree
Hide file tree
Showing 17 changed files with 1,637 additions and 6 deletions.
@@ -0,0 +1,5 @@
type X3<T> = T extends [infer U extends number] ? MustBeNumber<U> : never;
type X4<T> = T extends [infer U extends number, infer U extends number] ? MustBeNumber<U> : never;
type X5<T> = T extends [infer U extends number, infer U] ? MustBeNumber<U> : never;
type X6<T> = T extends [infer U, infer U extends number] ? MustBeNumber<U> : never;
type X7<T> = T extends [infer U extends string, infer U extends number] ? U : never;
@@ -0,0 +1,5 @@
type X3<T> = T extends [infer U extends number] ? MustBeNumber<U> : never;
type X4<T> = T extends [infer U extends number, infer U extends number] ? MustBeNumber<U> : never;
type X5<T> = T extends [infer U extends number, infer U] ? MustBeNumber<U> : never;
type X6<T> = T extends [infer U, infer U extends number] ? MustBeNumber<U> : never;
type X7<T> = T extends [infer U extends string, infer U extends number] ? U : never;
68 changes: 63 additions & 5 deletions packages/babel-parser/src/plugins/typescript/index.js
Expand Up @@ -1271,18 +1271,37 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.expectContextual(tt._infer);
const typeParameter = this.startNode();
typeParameter.name = this.tsParseTypeParameterName();
typeParameter.constraint = this.tsTryParse(() =>
this.tsParseConstraintForInferType(),
);
node.typeParameter = this.finishNode(typeParameter, "TSTypeParameter");
return this.finishNode(node, "TSInferType");
}

tsParseConstraintForInferType() {
if (this.eat(tt._extends)) {
const constraint = this.tsInDisallowConditionalTypesContext(() =>
this.tsParseType(),
);
if (
this.state.inDisallowConditionalTypesContext ||
!this.match(tt.question)
) {
return constraint;
}
}
}

tsParseTypeOperatorOrHigher(): N.TsType {
const isTypeOperator =
tokenIsTSTypeOperator(this.state.type) && !this.state.containsEsc;
return isTypeOperator
? this.tsParseTypeOperator()
: this.isContextual(tt._infer)
? this.tsParseInferType()
: this.tsParseArrayTypeOrHigher();
: this.tsInAllowConditionalTypesContext(() =>
this.tsParseArrayTypeOrHigher(),
);
}

tsParseUnionOrIntersectionType(
Expand Down Expand Up @@ -1516,16 +1535,31 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// Need to set `state.inType` so that we don't parse JSX in a type context.
assert(this.state.inType);
const type = this.tsParseNonConditionalType();
if (this.hasPrecedingLineBreak() || !this.eat(tt._extends)) {

if (
this.state.inDisallowConditionalTypesContext ||
this.hasPrecedingLineBreak() ||
!this.eat(tt._extends)
) {
return type;
}
const node: N.TsConditionalType = this.startNodeAtNode(type);
node.checkType = type;
node.extendsType = this.tsParseNonConditionalType();

node.extendsType = this.tsInDisallowConditionalTypesContext(() =>
this.tsParseNonConditionalType(),
);

this.expect(tt.question);
node.trueType = this.tsParseType();
node.trueType = this.tsInAllowConditionalTypesContext(() =>
this.tsParseType(),
);

this.expect(tt.colon);
node.falseType = this.tsParseType();
node.falseType = this.tsInAllowConditionalTypesContext(() =>
this.tsParseType(),
);

return this.finishNode(node, "TSConditionalType");
}

Expand Down Expand Up @@ -1668,6 +1702,30 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}

tsInDisallowConditionalTypesContext<T>(cb: () => T): T {
const oldInDisallowConditionalTypesContext =
this.state.inDisallowConditionalTypesContext;
this.state.inDisallowConditionalTypesContext = true;
try {
return cb();
} finally {
this.state.inDisallowConditionalTypesContext =
oldInDisallowConditionalTypesContext;
}
}

tsInAllowConditionalTypesContext<T>(cb: () => T): T {
const oldInDisallowConditionalTypesContext =
this.state.inDisallowConditionalTypesContext;
this.state.inDisallowConditionalTypesContext = false;
try {
return cb();
} finally {
this.state.inDisallowConditionalTypesContext =
oldInDisallowConditionalTypesContext;
}
}

tsEatThenParseType(token: TokenType): N.TsType | typeof undefined {
return !this.match(token) ? undefined : this.tsNextThenParseType();
}
Expand Down
1 change: 1 addition & 0 deletions packages/babel-parser/src/tokenizer/state.js
Expand Up @@ -75,6 +75,7 @@ export default class State {
hasFlowComment: boolean = false;
isAmbientContext: boolean = false;
inAbstractClass: boolean = false;
inDisallowConditionalTypesContext: boolean = false;

// For the Hack-style pipelines plugin
topicContext: TopicContextState = {
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-parser/src/types.js
Expand Up @@ -1476,7 +1476,7 @@ export type TsConditionalType = TsTypeBase & {

export type TsInferType = TsTypeBase & {
type: "TSInferType",
typeParameter: TypeParameter,
typeParameter: TsTypeParameter,
};

export type TsParenthesizedType = TsTypeBase & {
Expand Down
@@ -0,0 +1 @@
type X<U, T> = T extends [infer U extends T ? U : T] ? U : T;
@@ -0,0 +1,3 @@
{
"BABEL_8_BREAKING": false
}
@@ -0,0 +1,115 @@
{
"type": "File",
"start":0,"end":61,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":61,"index":61}},
"program": {
"type": "Program",
"start":0,"end":61,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":61,"index":61}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSTypeAliasDeclaration",
"start":0,"end":61,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":61,"index":61}},
"id": {
"type": "Identifier",
"start":5,"end":6,"loc":{"start":{"line":1,"column":5,"index":5},"end":{"line":1,"column":6,"index":6},"identifierName":"X"},
"name": "X"
},
"typeParameters": {
"type": "TSTypeParameterDeclaration",
"start":6,"end":12,"loc":{"start":{"line":1,"column":6,"index":6},"end":{"line":1,"column":12,"index":12}},
"params": [
{
"type": "TSTypeParameter",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8}},
"name": "U"
},
{
"type": "TSTypeParameter",
"start":10,"end":11,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":11,"index":11}},
"name": "T"
}
]
},
"typeAnnotation": {
"type": "TSConditionalType",
"start":15,"end":60,"loc":{"start":{"line":1,"column":15,"index":15},"end":{"line":1,"column":60,"index":60}},
"checkType": {
"type": "TSTypeReference",
"start":15,"end":16,"loc":{"start":{"line":1,"column":15,"index":15},"end":{"line":1,"column":16,"index":16}},
"typeName": {
"type": "Identifier",
"start":15,"end":16,"loc":{"start":{"line":1,"column":15,"index":15},"end":{"line":1,"column":16,"index":16},"identifierName":"T"},
"name": "T"
}
},
"extendsType": {
"type": "TSTupleType",
"start":25,"end":52,"loc":{"start":{"line":1,"column":25,"index":25},"end":{"line":1,"column":52,"index":52}},
"elementTypes": [
{
"type": "TSConditionalType",
"start":26,"end":51,"loc":{"start":{"line":1,"column":26,"index":26},"end":{"line":1,"column":51,"index":51}},
"checkType": {
"type": "TSInferType",
"start":26,"end":33,"loc":{"start":{"line":1,"column":26,"index":26},"end":{"line":1,"column":33,"index":33}},
"typeParameter": {
"type": "TSTypeParameter",
"start":32,"end":33,"loc":{"start":{"line":1,"column":32,"index":32},"end":{"line":1,"column":33,"index":33}},
"name": "U"
}
},
"extendsType": {
"type": "TSTypeReference",
"start":42,"end":43,"loc":{"start":{"line":1,"column":42,"index":42},"end":{"line":1,"column":43,"index":43}},
"typeName": {
"type": "Identifier",
"start":42,"end":43,"loc":{"start":{"line":1,"column":42,"index":42},"end":{"line":1,"column":43,"index":43},"identifierName":"T"},
"name": "T"
}
},
"trueType": {
"type": "TSTypeReference",
"start":46,"end":47,"loc":{"start":{"line":1,"column":46,"index":46},"end":{"line":1,"column":47,"index":47}},
"typeName": {
"type": "Identifier",
"start":46,"end":47,"loc":{"start":{"line":1,"column":46,"index":46},"end":{"line":1,"column":47,"index":47},"identifierName":"U"},
"name": "U"
}
},
"falseType": {
"type": "TSTypeReference",
"start":50,"end":51,"loc":{"start":{"line":1,"column":50,"index":50},"end":{"line":1,"column":51,"index":51}},
"typeName": {
"type": "Identifier",
"start":50,"end":51,"loc":{"start":{"line":1,"column":50,"index":50},"end":{"line":1,"column":51,"index":51},"identifierName":"T"},
"name": "T"
}
}
}
]
},
"trueType": {
"type": "TSTypeReference",
"start":55,"end":56,"loc":{"start":{"line":1,"column":55,"index":55},"end":{"line":1,"column":56,"index":56}},
"typeName": {
"type": "Identifier",
"start":55,"end":56,"loc":{"start":{"line":1,"column":55,"index":55},"end":{"line":1,"column":56,"index":56},"identifierName":"U"},
"name": "U"
}
},
"falseType": {
"type": "TSTypeReference",
"start":59,"end":60,"loc":{"start":{"line":1,"column":59,"index":59},"end":{"line":1,"column":60,"index":60}},
"typeName": {
"type": "Identifier",
"start":59,"end":60,"loc":{"start":{"line":1,"column":59,"index":59},"end":{"line":1,"column":60,"index":60},"identifierName":"T"},
"name": "T"
}
}
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
type X<U, T> = T extends [infer U extends T ? U : T] ? U : T;
@@ -0,0 +1,3 @@
{
"BABEL_8_BREAKING": true
}
@@ -0,0 +1,127 @@
{
"type": "File",
"start":0,"end":61,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":61,"index":61}},
"program": {
"type": "Program",
"start":0,"end":61,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":61,"index":61}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSTypeAliasDeclaration",
"start":0,"end":61,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":61,"index":61}},
"id": {
"type": "Identifier",
"start":5,"end":6,"loc":{"start":{"line":1,"column":5,"index":5},"end":{"line":1,"column":6,"index":6},"identifierName":"X"},
"name": "X"
},
"typeParameters": {
"type": "TSTypeParameterDeclaration",
"start":6,"end":12,"loc":{"start":{"line":1,"column":6,"index":6},"end":{"line":1,"column":12,"index":12}},
"params": [
{
"type": "TSTypeParameter",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8}},
"name": {
"type": "Identifier",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"U"},
"name": "U"
}
},
{
"type": "TSTypeParameter",
"start":10,"end":11,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":11,"index":11}},
"name": {
"type": "Identifier",
"start":10,"end":11,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":11,"index":11},"identifierName":"T"},
"name": "T"
}
}
]
},
"typeAnnotation": {
"type": "TSConditionalType",
"start":15,"end":60,"loc":{"start":{"line":1,"column":15,"index":15},"end":{"line":1,"column":60,"index":60}},
"checkType": {
"type": "TSTypeReference",
"start":15,"end":16,"loc":{"start":{"line":1,"column":15,"index":15},"end":{"line":1,"column":16,"index":16}},
"typeName": {
"type": "Identifier",
"start":15,"end":16,"loc":{"start":{"line":1,"column":15,"index":15},"end":{"line":1,"column":16,"index":16},"identifierName":"T"},
"name": "T"
}
},
"extendsType": {
"type": "TSTupleType",
"start":25,"end":52,"loc":{"start":{"line":1,"column":25,"index":25},"end":{"line":1,"column":52,"index":52}},
"elementTypes": [
{
"type": "TSConditionalType",
"start":26,"end":51,"loc":{"start":{"line":1,"column":26,"index":26},"end":{"line":1,"column":51,"index":51}},
"checkType": {
"type": "TSInferType",
"start":26,"end":33,"loc":{"start":{"line":1,"column":26,"index":26},"end":{"line":1,"column":33,"index":33}},
"typeParameter": {
"type": "TSTypeParameter",
"start":32,"end":33,"loc":{"start":{"line":1,"column":32,"index":32},"end":{"line":1,"column":33,"index":33}},
"name": {
"type": "Identifier",
"start":32,"end":33,"loc":{"start":{"line":1,"column":32,"index":32},"end":{"line":1,"column":33,"index":33},"identifierName":"U"},
"name": "U"
}
}
},
"extendsType": {
"type": "TSTypeReference",
"start":42,"end":43,"loc":{"start":{"line":1,"column":42,"index":42},"end":{"line":1,"column":43,"index":43}},
"typeName": {
"type": "Identifier",
"start":42,"end":43,"loc":{"start":{"line":1,"column":42,"index":42},"end":{"line":1,"column":43,"index":43},"identifierName":"T"},
"name": "T"
}
},
"trueType": {
"type": "TSTypeReference",
"start":46,"end":47,"loc":{"start":{"line":1,"column":46,"index":46},"end":{"line":1,"column":47,"index":47}},
"typeName": {
"type": "Identifier",
"start":46,"end":47,"loc":{"start":{"line":1,"column":46,"index":46},"end":{"line":1,"column":47,"index":47},"identifierName":"U"},
"name": "U"
}
},
"falseType": {
"type": "TSTypeReference",
"start":50,"end":51,"loc":{"start":{"line":1,"column":50,"index":50},"end":{"line":1,"column":51,"index":51}},
"typeName": {
"type": "Identifier",
"start":50,"end":51,"loc":{"start":{"line":1,"column":50,"index":50},"end":{"line":1,"column":51,"index":51},"identifierName":"T"},
"name": "T"
}
}
}
]
},
"trueType": {
"type": "TSTypeReference",
"start":55,"end":56,"loc":{"start":{"line":1,"column":55,"index":55},"end":{"line":1,"column":56,"index":56}},
"typeName": {
"type": "Identifier",
"start":55,"end":56,"loc":{"start":{"line":1,"column":55,"index":55},"end":{"line":1,"column":56,"index":56},"identifierName":"U"},
"name": "U"
}
},
"falseType": {
"type": "TSTypeReference",
"start":59,"end":60,"loc":{"start":{"line":1,"column":59,"index":59},"end":{"line":1,"column":60,"index":60}},
"typeName": {
"type": "Identifier",
"start":59,"end":60,"loc":{"start":{"line":1,"column":59,"index":59},"end":{"line":1,"column":60,"index":60},"identifierName":"T"},
"name": "T"
}
}
}
}
],
"directives": []
}
}
@@ -0,0 +1,7 @@
type X3<T> = T extends [infer U extends number] ? MustBeNumber<U> : never;
type X4<T> = T extends [infer U extends number, infer U extends number] ? MustBeNumber<U> : never;
type X5<T> = T extends [infer U extends number, infer U] ? MustBeNumber<U> : never;
type X6<T> = T extends [infer U, infer U extends number] ? MustBeNumber<U> : never;
type X7<T> = T extends [infer U extends string, infer U extends number] ? U : never;
type X8<U, T> = T extends infer U extends number ? U : T;
type X9<U, T> = T extends (infer U extends number ? U : T) ? U : T;

0 comments on commit 59d24a4

Please sign in to comment.