Closed as not planned
Closed as not planned
Description
π Search Terms
"getDeclarations", "ts.Declaration", "returns undefined"
π Version & Regression Information
- I was unable to test this on prior versions because version 4 does not support
ts.createProgram
function
β― Playground Link
https://github.com/eddeee888/typescript-type-getdeclarations-bug
π» Code
// shared.ts
type Generated<S> = ColumnType<S, S | undefined, S>;
type ColumnType<
SelectType,
InsertType = SelectType,
UpdateType = SelectType
> = {
readonly __select__: SelectType;
readonly __insert__: InsertType;
readonly __update__: UpdateType;
};
type DrainOuterGeneric<T> = [T] extends [unknown] ? T : never;
type IfNotNever<T, K> = T extends never ? never : K;
type SelectType<T> = T extends ColumnType<infer S, any, any> ? S : T;
type NonNeverSelectKeys<R> = {
[K in keyof R]: IfNotNever<SelectType<R[K]>, K>;
}[keyof R];
// 1. Selectable is a complex generic type
// It strips all generics from the properties of an interface/type
export type Selectable<R> = DrainOuterGeneric<{
[K in NonNeverSelectKeys<R>]: SelectType<R[K]>;
}>;
export interface BookTable {
id: Generated<number>;
isbn: string;
next_book_in_series_id: number | null;
previous_book_in_series_id: number | null;
}
// source-error.ts
import type { BookTable, Selectable } from "./shared";
/**
* Wrapping in `Selectable` results in `.getDeclarations` returns `undefined`
*/
export type BookMapper = Selectable<BookTable>;
// main.ts
import * as ts from "typescript";
const program = ts.createProgram([process.env.SOURCE || ""], {});
const checker = program.getTypeChecker();
for (const sourceFile of program.getSourceFiles()) {
if (!sourceFile.isDeclarationFile) {
ts.forEachChild(sourceFile, visit);
}
}
function visit(node: ts.Node): void {
if (
ts.isTypeAliasDeclaration(node) &&
node.name &&
node.name.text === "BookMapper"
) {
const type = checker.getTypeAtLocation(node);
console.dir(
{
properties: type.getProperties().map((prop) => {
return {
propName: prop.getName(),
declarations: prop.getDeclarations(), // this should get the type of each `BookTable`'s prop, but it is returning undefined when `Selectable` is used
};
}),
},
{ depth: 4 }
);
}
}
π Actual behavior
prop.getDeclarations()
in main.ts
should return the type of each declaration
π Expected behavior
prop.getDeclarations()
in main.ts
returns undefined
Additional information about the issue
It works fine if:
Selectable
is not used to wrapBookTable
- A simpler generic is used to wrap
BookTable
e.g.type Test<T> = T & { __test: boolean }
I can see BookMapper
's final types being recognised correctly by Language Server (image blow), not sure if I'm missing something obvious.
