gristlabs / ts-interface-builder

Compile TypeScript interfaces into a description that allows runtime validation
Apache License 2.0
132 stars 28 forks source link

Possibility to support "Node IndexedAccessType" #37

Open xzilja opened 3 years ago

xzilja commented 3 years ago
export interface ICharacter {
  id: string;
  username: string;
}

export interface ICreateCharacterArguments {
  username: ICharacter['username'];
};

Currently generating from this file fails with following error Error: Node IndexedAccessType not supported by ts-interface-builder: ICharacter['username']

EDIT: Additional context on this type https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html

xzilja commented 3 years ago

I'm trying to play around with this and essentially tweaked

https://github.com/gristlabs/ts-interface-builder/blob/5c0fa5b393743b18e0a2987dd7126114838f57e4/lib/index.ts#L96-L97

and added additional case at the end

case ts.SyntaxKind.IndexedAccessType:
         return this._compileIndexSignatureDeclaration(node);

But I am then getting stuck here https://github.com/gristlabs/ts-interface-builder/blob/5c0fa5b393743b18e0a2987dd7126114838f57e4/lib/index.ts#L261

I am not sure where this type needs to be set / added at the moment

dsagal commented 3 years ago

IndexedAccessType is a different kind of node than an IndexSignatureDeclaration. So your case should look like

case ts.SyntaxKind.IndexedAccessType:
   return this._compileIndexedAccessType(node as ts.IndexedAccessTypeNode);

You can learn more about that node type by finding it in the TypeScript source code: TypeScript/src/compiler/types.ts.

As for what code ts-interface-builder should actually emit in this case, that's the hard part. I think it requires a new kind of node that ts-interface-checker would have to support, maybe something like t.typeProp("ICharacter", "username"). But TypeScript is actually more flexible -- https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html -- so to support it better, it perhaps should be t.typeProp("ICharacter", t.lit("username")). And it would need to be implemented on the ts-interface-checker side.

There might be other ways of doing it -- e.g. if ICharacter["username"] is known to be string, just to emit "string". There is enough inference in TypeScript compiler that it's probably possible, at least in some cases, but probably not in general.