-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New Syntax: module implements Type #46942
Comments
Love any time saving features like this personally. Love TS, hate having to type it out so much haha. |
This would be particularly useful for gradually typing a JS codebase. Iβve been trying to find a solution to use declaration files for codebases I maintain (as opposed to Some bikesheds to consider:
|
Duplicate of #38511. |
I could see a similar case for a GraphQL service with type generation from a schema. Example, let's consider the following graphql type:
type Movie {
id: ID!
name: String!
tagline: String
overview: String!
releaseDate: DateTime
runtime: Int
cast(limit: Int): [Person!]!
crew(limit: Int): [Person!]!
recommended(
page: Int= 1
limit: Int
): [Movie!]!
similar(
page: Int = 1
limit: Int
): [Movie!]!
} Which would generate the following type:
import { Parent, Context, Info } from "./resolverTypes"
import { Person } from "./Person"
export interface Movie {
id: string;
name: string;
tagline?: string;
overview: string;
releaseDate?: Date;
runtime?: number;
cast: (parent: Parent, args: { limit: number; }, context: Context, info: Info) => Person[]
crew: (parent: Parent, args: { limit: number; }, context: Context, info: Info) => Person[]
recommended: (parent: Parent, args: { page?: number; limit: number; }, context: Context, info: Info) => Movie[]
similar: (parent: Parent, args: { page?: number; limit: number; }, context: Context, info: Info) => Movie[]
} Now if you had a module that exported resolvers for this type, you could then automatically type the exports like so:
import { type Movie } from "../../generated/Movie"
module implements Partial<Movie>
export const cast = (_, { limit }) => { /* ... */ }
export const crew = (_, { limit }) => { /* ... */ }
export const recommended = (_, { page = 1, limit }) => { /* ... */ }
export const similar = (_, { page = 1, limit }) => { /* ... */ } In this case I would want to be able to have a partial implementation, so that my named exports are automatically typed but I don't get any errors for missing exports (I may have default resolvers for those, for example). Maybe for the example above, when another module imports this one, Typescript would be smart enough to know that Just my two cents. Would like to hear what others have to say before commenting further. Neat idea @kentcdodds! |
That's a great proposal. Framework and library writers can benefit from this greatly! On a technical level, I wonder if such module validation falls into the way TypeScript works. From my limited understanding, TypeScript takes the files you define in // file.ts
// TypeScript can annotate export types for "*.ext"
// based on your custom "declare module" declarations.
import data from './module.ext'
// TypeScript validates the types you declare
// immediately in this module.
type MyType = {}
// TypeScript validates the types imported from other
// modules (as long as they fall under the "include" paths.
import type { ExternalType } from './extraneous'
function action(a: ExternalType) {} Neither of these behaviors would satisfy the proposed module-wide validation. If I understand the intention correctly, the idea is for a certain group of modules to have a typed export type. Since the surface at which such validation occurs doesn't equal the consumer's surface (you're not expected to The closest thing in terms of behavior is annotating export types of imported modules: // global.d.ts
// Whenever you "import X from "foo.png"...
declare module "*.png" {
const content: string
// ...anotate its default export as a string.
export default content
} That does, however, imply that |
I must admit - I like the idea But it seems specific for the generation of module interfaces, where it's (within the proposal) implied in the code rather than a separate definition file I understand the sentiment But is the idea maybe diluting the concept of types and interfaces and their separation with definition files? I think the crux of the situation is more within the maintenance aspect rather than a syntax implementation necessarily? |
Although they are similar, the proposed syntax is different |
Sure the proposed syntax is different, but the two issue ultimately talks about the same idea π |
As @intrnl said, they're the same idea.
|
Great proposal! This would greatly bridge the gap in the DX between developing in typescript with classes and a more module based approach. Personally, I prefer to use modules instead of classes, so this sort of feature is sorely missed. |
Closing & locking due to twitter incoming traffic that hasn't seen there's already an issue for this. Thanks! |
Suggestion
π Search Terms
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
I want to add a new syntax for setting export types for a module:
Shorthand syntax:
Default type export shorthand syntax:
Note: I'm much more interested in the feature than the syntax.
π Motivating Example
I want to be able to do this:
See, you can have a conventional module format and get automatic typings for everything the module is supposed to export.
π» Use Cases
Some libraries have conventions for modules. I thinking specifically of Remix, but other frameworks have similar conventions (like Next.js, SvelteKit, and Storybook). For example, in Remix a route module should export the following interface:
The issue here is that as a user of the convention, I have to type everything I export. This comes with two problems:
So, for example, I currently have to do this:
What I want to be able to do is this:
Please let me know if you need any other details. Thanks for taking the time to read and consider!
The text was updated successfully, but these errors were encountered: