Closed evantahler closed 2 months ago
Is this actually possible?
I don't know... but it would be very helpful!
There are tools like typedoc
which somehow are able to build documentation sites from TS/TSX files...
This is not possible; unless you think it is acceptable to have the function somehow read the original typescript source code and parse it. Note that it's even worse than just reading the file source code, you have to read the original TS source code. In most cases that file is not even available. For example, most npm packages written in typescript do not publish the TS source code as part of the package, only the compiled code.
The reason this is not possible otherwise is because TypeScript has full type-erasure, which implies in particular that a type signature cannot change the runtime behavior of a program (unless the program reads its own source code).
However, turning this around is very possible. It is possible to have a JsObjectToType
utility. Would that work?
Thanks @papb! Doing it in reverse with something like JsObjectToType
might be useful... if we could get an instance of the class using the type, we could probably get the same outcome:
interface Car {
wheels: number;
manufacturer: string;
color: string;
licensePlate: string;
}
const car = new Car()
console.log(`Car objects require: ${JsObjectToType(Car)}`)
@evantahler That won't work as well... It is not possible to call new
on an interface.
I was talking about something like:
// Below is a normal object that exists at runtime (JS)
const CAR_TYPE_STRUCTURE = {
wheels: 'number';
manufacturer: 'string';
color: 'string';
licensePlate: 'string';
} as const;
console.log('Car objects require:', CAR_TYPE_STRUCTURE);
// Below is a type declared as a function of that object. The type only exists at compile-time.
type Car = JsObjectToType<typeof CAR_TYPE_STRUCTURE>;
function useCar(car: Car) {
// ...
}
Note: I am saying this is possible, but I am not sure whether this is good or not :sweat_smile:
Thanks for all the brainstorming on this @papb! Maybe if I share the specifics of my use case, it might spark some ideas.
I maintain Actionhero (https://www.actionherojs.com), and we've been going "all in" on Typescript as of late. Every Action is well-defined class:
import { Action } from "actionhero";
class SleepAction extends Action {
constructor() {
super();
this.name = "sleepTest";
this.description = "I will sleep for some amount of time";
this.inputs = {
sleepDuration: {
required: true,
formatter: (n) => parseInt(n),
default: () => 1000,
},
};
}
async sleep (time: number) {
await new Promise(resolve => setTimeout(resolve, time));
}
async run ({ params }) {
await this.sleep(params.sleepDuration);
return { success: true};
}
}
I'm trying to figure out a way to determine the class of params
as it enters the run method. We've already done validation and formatting on the user input to ensure that params.sleepDuration
is a number, parsed with pareInt()
and if it wasn't provided, will have a default of 1000
. Ideally, there would be some way to add a type to this.inputs
, perhaps a type:number
, to tell the compiler that {params}: {params: { sleepDuration: number }}
Here's the full example of the action: https://github.com/actionhero/actionhero/blob/master/src/actions/sleepTest.ts
Ideally, there would be some way to add a type to
this.inputs
, perhaps atype:number
, to tell the compiler that{params}: {params: { sleepDuration: number }}
This can be done nicely, I can help you with that. But first, this does not seem to be what you requested in the first post. If you just want to "tell the compiler about something", that is very doable. But I think what you seem to want is to give a helpful error message to the user, since you wrote:
console.log(`Car objects require: ${TypeToJSObject<Car>}`)
I will think about a way to provide an error message like this in a nice way and let you know.
This can be done nicely, I can help you with that.
Thanks @papb! I'd love your help figuring out how to determine types from inputs
. Let's move that conversation over to https://github.com/actionhero/actionhero/issues/1400. Thank you!
What you requested in your first post is not possible at all in TypeScript. In the future TS might support compilation plugins that generate code, but that's still not possible in type-fest. Even then, I think it's a terrible idea.
In https://github.com/sindresorhus/type-fest/issues/133#issuecomment-707401534 it looks like you're looking for zod: https://zod.dev
Example from its docs
import { z } from "zod";
const User = z.object({
username: z.string(),
});
User.parse({ username: "Ludwig" });
// extract the inferred type
type User = z.infer<typeof User>;
// { username: string }
Hello!
It might be interesting to have a utility that allows us to get the Object-style notation for a type/interface and make it available for Javascript to see, as an object. This could be useful for generating documentation, error creation, or API documentation.
Something like:
Upvote & Fund