Skip to content

Commit 15eb409

Browse files
authored
Don't create bad types in type literal substituion in destructured arguments (#71)
In `getPropType()` we sometimes notice that there is a type param substitution so that the text of the type of the prop node does not match the text of its definition node. In this case, we were calling `typeToIR` twice and throwing away the first outcome. However, now `typeToIR()` can cause side effects so we should make sure to only call it when we need the outcome.
1 parent f9fa0c9 commit 15eb409

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

type-generation/src/astToIR.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -884,18 +884,20 @@ export class Converter {
884884
const name = prop.getName();
885885
const optional = !!prop.getQuestionTokenNode();
886886
// Try to get resolved type from the parameter type, fallback to interface definition
887-
let type: TypeIR = this.typeToIR(prop.getTypeNode()!, optional);
888887
const propSymbol = paramType?.getProperty(name);
889888
if (!propSymbol) {
890-
return type;
889+
return this.typeToIR(prop.getTypeNode()!, optional);
891890
}
892891
const propType = propSymbol.getTypeAtLocation(lastParam!);
893892
// Convert the resolved type by getting a dummy type node
894893
// This is a bit hacky. Would be nice to create a synthetic node more
895894
// directly.
896895
const tempType = propType.getText();
897-
if (tempType === prop.getTypeNode()?.getText()) {
898-
return type;
896+
if (
897+
tempType.replaceAll(/\s/g, "") ===
898+
prop.getTypeNode()?.getText().replaceAll(/\s/g, "")
899+
) {
900+
return this.typeToIR(prop.getTypeNode()!, optional);
899901
}
900902

901903
if (propType.isTypeParameter()) {
@@ -920,6 +922,7 @@ export class Converter {
920922
const typeAliasDecl = tempFile.getTypeAliases()[0];
921923
const dummyTypeNode = typeAliasDecl.getTypeNode()!;
922924
const res = this.typeToIR(dummyTypeNode, optional);
925+
this.popNameContext();
923926
// Don't remove the temp file, it causes crashes. TODO: Fix this?
924927
return res;
925928
};

type-generation/tests/a.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,6 +1902,33 @@ describe("emit", () => {
19021902
`).trim(),
19031903
);
19041904
});
1905+
it("type literal in destructured option arg", () => {
1906+
const res = emitFile(`
1907+
interface O<T> {
1908+
x?: { a: T; };
1909+
;
1910+
declare function f(options: O<string>): void;
1911+
`);
1912+
assert.strictEqual(
1913+
removeTypeIgnores(res.slice(1).join("\n\n")),
1914+
dedent(`
1915+
@overload
1916+
def f(options: O_iface[str], /) -> None: ...
1917+
1918+
@overload
1919+
def f(*, x: f__Sig0_iface | None = None) -> None: ...
1920+
1921+
class O_iface[T](Protocol):
1922+
x: O_iface__x_iface | None = ...
1923+
1924+
class f__Sig0_iface(Protocol):
1925+
a: str = ...
1926+
1927+
class O_iface__x_iface(Protocol):
1928+
a: T = ...
1929+
`).trim(),
1930+
);
1931+
});
19051932
});
19061933
describe("adjustments", () => {
19071934
it("setTimeout", () => {

0 commit comments

Comments
 (0)