Skip to content

Commit

Permalink
Fix #2451
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerrit0 committed Dec 27, 2023
1 parent aaa5f35 commit a636bd5
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -13,6 +13,7 @@

### Bug Fixes

- Fix crash when converting some complicated union/intersection types, #2451.
- Navigation triangle markers should no longer display on a separate line with some font settings, #2457.
- `@group` and `@category` organization is now applied later to allow inherited comments to create groups/categories, #2459.
- Keyword syntax highlighting introduced in 0.25.4 was not always applied to keywords.
Expand Down
2 changes: 2 additions & 0 deletions scripts/testcase.js
Expand Up @@ -57,6 +57,8 @@ async function main() {
);
if (!code) {
console.log("No codeblock found");
const file = `src/test/converter2/issues/gh${issue}.ts`;
await exec(`code ${file}`);
return;
}

Expand Down
21 changes: 11 additions & 10 deletions src/lib/converter/types.ts
Expand Up @@ -132,6 +132,17 @@ export function convertType(
return requestBugReport(context, typeOrNode);
}

// TS 4.2 added this to enable better tracking of type aliases.
// We need to check it here, not just in the union checker, because typeToTypeNode
// will use the origin when serializing
if (
typeOrNode.isUnion() &&
typeOrNode.origin &&
!typeOrNode.origin.isUnion()
) {
return convertType(context, typeOrNode.origin);
}

// IgnoreErrors is important, without it, we can't assert that we will get a node.
const node = context.checker.typeToTypeNode(
typeOrNode,
Expand Down Expand Up @@ -1011,11 +1022,6 @@ const typeOperatorConverter: TypeConverter<ts.TypeOperatorNode> = {
// keyof will only show up with generic functions, otherwise it gets eagerly
// resolved to a union of strings.
if (node.operator === ts.SyntaxKind.KeyOfKeyword) {
// TS 4.2 added this to enable better tracking of type aliases.
if (type.isUnion() && type.origin) {
return convertType(context, type.origin);
}

// There's probably an interface for this somewhere... I couldn't find it.
const targetType = (type as ts.Type & { type: ts.Type }).type;
return new TypeOperatorType(
Expand All @@ -1038,11 +1044,6 @@ const unionConverter: TypeConverter<ts.UnionTypeNode, ts.UnionType> = {
);
},
convertType(context, type) {
// TS 4.2 added this to enable better tracking of type aliases.
if (type.origin) {
return convertType(context, type.origin);
}

return new UnionType(
type.types.map((type) => convertType(context, type)),
);
Expand Down
15 changes: 15 additions & 0 deletions src/test/converter2/issues/gh2451.ts
@@ -0,0 +1,15 @@
export type Foo = FooA | FooB;

export interface BaseFoo<T extends string> {
type: T;

is<Type extends string>(
type: Type,
): this is Foo & {
type: Type;
};
}

export interface FooA extends BaseFoo<"A"> {}

export interface FooB extends BaseFoo<"B"> {}
9 changes: 8 additions & 1 deletion src/test/issues.c2.test.ts
Expand Up @@ -27,7 +27,7 @@ import {
getConverter2Program,
} from "./programs";
import { TestLogger } from "./TestLogger";
import { getComment, getLinks, query } from "./utils";
import { getComment, getLinks, query, querySig } from "./utils";

const base = getConverter2Base();
const app = getConverter2App();
Expand Down Expand Up @@ -1225,4 +1225,11 @@ describe("Issue Tests", () => {
equal(boolEq.signatures![0].parameters![0].type?.toString(), "boolean");
equal(numEq.signatures![0].parameters![0].type?.toString(), "number");
});

it("Handles unions created due to union within intersection, #2451", () => {
const project = convert();

const is = querySig(project, "FooA.is");
equal(is.type?.toString(), "this is Foo & Object");
});
});

0 comments on commit a636bd5

Please sign in to comment.