transform-spread: create TS types (not Flow) when using TS (#11378)

*  add test fixture

*  add removeTypeDuplicates for typescript

*  add createTSUnionType for typescript

* 💊 fix ConditionalExpression for typescript

* 💊 fix ConditionalExpression

* 💊 fix added test case

*  add new line at the end of the file

* 💊 types.every(f) => f(types[0])

* 🔄 bug => foo

*  add TSBaseType

*  add conditions NOT to break backward compatibility
This commit is contained in:
beraliv
2020-04-15 22:47:28 +03:00
committed by GitHub
parent c85aafdff6
commit 6b8f6ab2de
11 changed files with 170 additions and 9 deletions

View File

@@ -1202,6 +1202,9 @@ export function assertTSTypeElement(node: Object, opts?: Object = {}): void {
export function assertTSType(node: Object, opts?: Object = {}): void {
assert("TSType", node, opts);
}
export function assertTSBaseType(node: Object, opts?: Object = {}): void {
assert("TSBaseType", node, opts);
}
export function assertNumberLiteral(node: Object, opts: Object): void {
console.trace(
"The node type NumberLiteral has been renamed to NumericLiteral",

View File

@@ -0,0 +1,19 @@
import { TSUnionType } from "../generated";
import removeTypeDuplicates from "../../modifications/typescript/removeTypeDuplicates";
/**
* Takes an array of `types` and flattens them, removing duplicates and
* returns a `UnionTypeAnnotation` node containg them.
*/
export default function createTSUnionType(
typeAnnotations: Array<Object>,
): Object {
const types = typeAnnotations.map(type => type.typeAnnotations);
const flattened = removeTypeDuplicates(types);
if (flattened.length === 1) {
return flattened[0];
} else {
return TSUnionType(flattened);
}
}

View File

@@ -51,3 +51,4 @@ export const JSX_TYPES = FLIPPED_ALIAS_KEYS["JSX"];
export const PRIVATE_TYPES = FLIPPED_ALIAS_KEYS["Private"];
export const TSTYPEELEMENT_TYPES = FLIPPED_ALIAS_KEYS["TSTypeElement"];
export const TSTYPE_TYPES = FLIPPED_ALIAS_KEYS["TSType"];
export const TSBASETYPE_TYPES = FLIPPED_ALIAS_KEYS["TSBaseType"];

View File

@@ -143,14 +143,14 @@ const tsKeywordTypes = [
for (const type of tsKeywordTypes) {
defineType(type, {
aliases: ["TSType"],
aliases: ["TSType", "TSBaseType"],
visitor: [],
fields: {},
});
}
defineType("TSThisType", {
aliases: ["TSType"],
aliases: ["TSType", "TSBaseType"],
visitor: [],
fields: {},
});
@@ -300,7 +300,7 @@ defineType("TSMappedType", {
});
defineType("TSLiteralType", {
aliases: ["TSType"],
aliases: ["TSType", "TSBaseType"],
visitor: ["literal"],
fields: {
literal: validateType([

View File

@@ -10,6 +10,7 @@ export * from "./asserts/generated";
// builders
export { default as createTypeAnnotationBasedOnTypeof } from "./builders/flow/createTypeAnnotationBasedOnTypeof";
export { default as createUnionTypeAnnotation } from "./builders/flow/createUnionTypeAnnotation";
export { default as createTSUnionType } from "./builders/typescript/createTSUnionType";
export * from "./builders/generated";
// clone

View File

@@ -0,0 +1,65 @@
import {
isTSAnyKeyword,
isTSUnionType,
isTSBaseType,
} from "../../validators/generated";
/**
* Dedupe type annotations.
*/
export default function removeTypeDuplicates(
nodes: Array<Object>,
): Array<Object> {
const generics = {};
const bases = {};
// store union type groups to circular references
const typeGroups = [];
const types = [];
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (!node) continue;
// detect duplicates
if (types.indexOf(node) >= 0) {
continue;
}
// this type matches anything
if (isTSAnyKeyword(node.type)) {
return [node];
}
// Analogue of FlowBaseAnnotation
if (isTSBaseType(node)) {
bases[node.type] = node;
continue;
}
if (isTSUnionType(node)) {
if (typeGroups.indexOf(node.types) < 0) {
nodes = nodes.concat(node.types);
typeGroups.push(node.types);
}
continue;
}
// TODO: add generic types
types.push(node);
}
// add back in bases
for (const type of Object.keys(bases)) {
types.push(bases[type]);
}
// add back in generics
for (const name of Object.keys(generics)) {
types.push(generics[name]);
}
return types;
}

View File

@@ -4611,6 +4611,36 @@ export function isTSType(node: ?Object, opts?: Object): boolean {
return false;
}
export function isTSBaseType(node: ?Object, opts?: Object): boolean {
if (!node) return false;
const nodeType = node.type;
if (
nodeType === "TSBaseType" ||
"TSAnyKeyword" === nodeType ||
"TSBooleanKeyword" === nodeType ||
"TSBigIntKeyword" === nodeType ||
"TSNeverKeyword" === nodeType ||
"TSNullKeyword" === nodeType ||
"TSNumberKeyword" === nodeType ||
"TSObjectKeyword" === nodeType ||
"TSStringKeyword" === nodeType ||
"TSSymbolKeyword" === nodeType ||
"TSUndefinedKeyword" === nodeType ||
"TSUnknownKeyword" === nodeType ||
"TSVoidKeyword" === nodeType ||
"TSThisType" === nodeType ||
"TSLiteralType" === nodeType
) {
if (typeof opts === "undefined") {
return true;
} else {
return shallowEqual(node, opts);
}
}
return false;
}
export function isNumberLiteral(node: ?Object, opts?: Object): boolean {
console.trace(
"The node type NumberLiteral has been renamed to NumericLiteral",