Skip to content

Commit

Permalink
TypeScript: Support conditional types syntax (babel#7404)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy authored and aminmarashi committed Mar 17, 2018
1 parent f2d543e commit ead9c85
Show file tree
Hide file tree
Showing 16 changed files with 587 additions and 1 deletion.
22 changes: 22 additions & 0 deletions packages/babel-generator/src/generators/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,28 @@ export function tsPrintUnionOrIntersectionType(node, sep) {
});
}

export function TSConditionalType(node) {
this.print(node.checkType);
this.space();
this.word("extends");
this.space();
this.print(node.extendsType);
this.space();
this.token("?");
this.space();
this.print(node.trueType);
this.space();
this.token(":");
this.space();
this.print(node.falseType);
}

export function TSInferType(node) {
this.token("infer");
this.space();
this.print(node.typeParameter);
}

export function TSParenthesizedType(node) {
this.token("(");
this.print(node.typeAnnotation, node);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
type Element<T> = T extends (infer U)[] ? U : T;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
type Element<T> = T extends (infer U)[] ? U : T;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let x: number extends string ? boolean : null;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let x: number extends string ? boolean : null;
29 changes: 29 additions & 0 deletions packages/babel-types/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1875,6 +1875,22 @@ Aliases: `TSTypeElement`

---

### tSConditionalType
```javascript
t.tsConditionalType(checkType, extendsType, trueType, falseType)
```

See also `t.isTSConditionalType(node, opts)` and `t.assertTSConditionalType(node, opts)`.

Aliases: `TSType`

- `checkType`: `TSType` (required)
- `extendsType`: `TSType` (required)
- `trueType`: `TSType` (required)
- `falseType`: `TSType` (required)

---

### tSConstructSignatureDeclaration
```javascript
t.tsConstructSignatureDeclaration(typeParameters, parameters, typeAnnotation)
Expand Down Expand Up @@ -2074,6 +2090,19 @@ Aliases: `TSType`

---

### tSInferType
```javascript
t.tsInferType(typeParameter)
```

See also `t.isTSInferType(node, opts)` and `t.assertTSInferType(node, opts)`.

Aliases: `TSType`

- `typeParameter`: `TSType` (required)

---

### tSInterfaceBody
```javascript
t.tsInterfaceBody(body)
Expand Down
9 changes: 9 additions & 0 deletions packages/babel-types/src/asserts/generated/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,15 @@ export function assertTSIntersectionType(
): void {
assert("TSIntersectionType", node, opts);
}
export function assertTSConditionalType(
node: Object,
opts?: Object = {},
): void {
assert("TSConditionalType", node, opts);
}
export function assertTSInferType(node: Object, opts?: Object = {}): void {
assert("TSInferType", node, opts);
}
export function assertTSParenthesizedType(
node: Object,
opts?: Object = {},
Expand Down
10 changes: 10 additions & 0 deletions packages/babel-types/src/builders/generated/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,16 @@ export function TSIntersectionType(...args: Array<any>): Object {
}
export { TSIntersectionType as tsIntersectionType };
export { TSIntersectionType as tSIntersectionType };
export function TSConditionalType(...args: Array<any>): Object {
return builder("TSConditionalType", ...args);
}
export { TSConditionalType as tsConditionalType };
export { TSConditionalType as tSConditionalType };
export function TSInferType(...args: Array<any>): Object {
return builder("TSInferType", ...args);
}
export { TSInferType as tsInferType };
export { TSInferType as tSInferType };
export function TSParenthesizedType(...args: Array<any>): Object {
return builder("TSParenthesizedType", ...args);
}
Expand Down
19 changes: 19 additions & 0 deletions packages/babel-types/src/definitions/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,25 @@ const unionOrIntersection = {
defineType("TSUnionType", unionOrIntersection);
defineType("TSIntersectionType", unionOrIntersection);

defineType("TSConditionalType", {
aliases: ["TSType"],
visitor: ["checkType", "extendsType", "trueType", "falseType"],
fields: {
checkType: validateType("TSType"),
extendsType: validateType("TSType"),
trueType: validateType("TSType"),
falseType: validateType("TSType"),
},
});

defineType("TSInferType", {
aliases: ["TSType"],
visitor: ["typeParameter"],
fields: {
typeParameter: validateType("TSType"),
},
});

defineType("TSParenthesizedType", {
aliases: ["TSType"],
visitor: ["typeAnnotation"],
Expand Down
6 changes: 6 additions & 0 deletions packages/babel-types/src/validators/generated/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,12 @@ export function isTSUnionType(node: Object, opts?: Object): boolean {
export function isTSIntersectionType(node: Object, opts?: Object): boolean {
return is("TSIntersectionType", node, opts);
}
export function isTSConditionalType(node: Object, opts?: Object): boolean {
return is("TSConditionalType", node, opts);
}
export function isTSInferType(node: Object, opts?: Object): boolean {
return is("TSInferType", node, opts);
}
export function isTSParenthesizedType(node: Object, opts?: Object): boolean {
return is("TSParenthesizedType", node, opts);
}
Expand Down
28 changes: 27 additions & 1 deletion packages/babylon/src/plugins/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -617,11 +617,22 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.finishNode(node, "TSTypeOperator");
}

tsParseInferType(): N.TsInferType {
const node = this.startNode();
this.expectContextual("infer");
const typeParameter = this.startNode();
typeParameter.name = this.parseIdentifierName(typeParameter.start);
node.typeParameter = this.finishNode(typeParameter, "TypeParameter");
return this.finishNode(node, "TSInferType");
}

tsParseTypeOperatorOrHigher(): N.TsType {
const operator = ["keyof", "unique"].find(kw => this.isContextual(kw));
return operator
? this.tsParseTypeOperator(operator)
: this.tsParseArrayTypeOrHigher();
: this.isContextual("infer")
? this.tsParseInferType()
: this.tsParseArrayTypeOrHigher();
}

tsParseUnionOrIntersectionType(
Expand Down Expand Up @@ -774,6 +785,21 @@ export default (superClass: Class<Parser>): Class<Parser> =>
tsParseType(): N.TsType {
// 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)) {
return type;
}
const node: N.TsConditionalType = this.startNodeAtNode(type);
node.checkType = type;
node.extendsType = this.tsParseNonConditionalType();
this.expect(tt.question);
node.trueType = this.tsParseType();
this.expect(tt.colon);
node.falseType = this.tsParseType();
return this.finishNode(node, "TSConditionalType");
}

tsParseNonConditionalType(): N.TsType {
if (this.tsIsStartOfFunctionType()) {
return this.tsParseFunctionOrConstructorType("TSFunctionType");
}
Expand Down
13 changes: 13 additions & 0 deletions packages/babylon/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,19 @@ export type TsIntersectionType = TsUnionOrIntersectionTypeBase & {
type: "TSIntersectionType",
};

export type TsConditionalType = TsTypeBase & {
type: "TSConditionalType",
checkType: TsType,
extendsType: TsType,
trueType: TsType,
falseType: tsType,
};

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

export type TsParenthesizedType = TsTypeBase & {
type: "TSParenthesizedType",
typeAnnotation: TsType,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
type Element<T> = T extends (infer U)[] ? U : T;
Loading

0 comments on commit ead9c85

Please sign in to comment.