Skip to content
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

Create a free type constructor #1

Open
Jackman3005 opened this issue Dec 7, 2022 · 2 comments
Open

Create a free type constructor #1

Jackman3005 opened this issue Dec 7, 2022 · 2 comments

Comments

@Jackman3005
Copy link

First off, thanks for the work you've put in in this library. It's quite incredible. The documentation is on par of libraries with 100x stars than you have. 🙏

At the bottom of your Guide page you have this little line:

Another option for removing boilerplate would be to contribute to the introduction of free type constructors into the language natively 😁

This is the only thing that is holding me back when using this library. I'm able to encapsulate nearly everything regarding the challenging typing I'm trying to accomplish, except that I require consumers of my function to create a free type for each of their use-cases. Would be awesome if there was a way for them to provide the type they already have to some sort of constructor (better if I can do that for them somehow) instead of having to know about/understand/maintain a free type.

Anyways, I have no idea how to accomplish this, but I wanted to start the thread for discussion and maybe someone way smarter than me can come along and contribute or provide some insight.

@geoffreytools
Copy link
Owner

geoffreytools commented Dec 7, 2022

Thanks a lot for your warm comment.

I don't know your specific use case but one thing that you can do to make people unaware of free-types and make it a little more user friendly is to bake the type parameters into fields, this way they don't need to understand how to defuse type constraints because it's already done, and they extend your contract, not Type itself:

// library code

import { Type, apply, A } from 'free-types';

export interface $Contract extends Type<[string], string> {
    str: A<this>
}

export type Foo<$T extends $Contract> = apply<$T, ['a']>
// user code

import { Foo, $Contract } from 'library';

interface $T extends $Contract {
    type: `prefix-${this['str']}`
}

type fooT = Foo<$T> // "prefix-a"

(playground)

The alternative with module augmentation would look like this, which I think is a lot more convoluted:

// library code

export interface UserTypeString<S extends string> { }

export type Foo<$T extends keyof UserTypeString<string>> = UserTypeString<'a'>[$T]
// user code

import { Foo } from 'library';

declare module 'library' {
    interface UserTypeString<S extends string> {
        SomeUserType: SomeUserType<S>
    }
}

type SomeUserType<S extends string> = `prefix-${S}`;

type fooT = Foo<'SomeUserType'>

I was considering as a next step to get my feet wet with a macro for automating type creation using custom transformers and ttypescript. Maybe later if I am brave I will get familiar with the guts of Typescript to try and bring something more substantial to the table than a user library.

The value of a macro for type creation would not be immense though, because users would still need to understand the difference between a normal type and a free type, how to care for their return type, the limitations they have on type constraints (no dependent or procedural type constraints), etc. but I have to admit boilerplate is the number 1 complaint I receive.

I didn't look much into it. Apparently, bundlers accept transformers already and I hope that setting up your IDE to use the installed version of typescript as the language server would be enough for live type checking to work (not sure about that).

@geoffreytools
Copy link
Owner

I made some progress on this issue. An intermediary result can be found in free-types-transform.

Writing the transformer the way I want it is actually quite trivial and I am not worried about limitations in that regard, but as expected the transform only applies to the emitted .d.ts files and I still don't know if a language service plugin supporting the kind of changes I made to the AST can be written, as it doesn't seem to have been designed for this purpose.

I chose ts-patch over ttypescript. It is more powerful and has very interesting plans for the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants