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

Ability to define "branded" types. #193

Open
indietyp opened this issue Dec 22, 2023 · 2 comments
Open

Ability to define "branded" types. #193

indietyp opened this issue Dec 22, 2023 · 2 comments
Labels
breaking change This will probs end up in the next major version.

Comments

@indietyp
Copy link

I am currently searching for a way to map TypeScript branded types, like https://github.com/kourge/ts-brand cleanly using specta. My current (flawed) approach is:

#[cfg_attr(feature = "wasm", derive(specta::Type))]
struct Brand<T, const MARKER: &'static str> {
    _marker: core::marker::PhantomData<T>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[cfg_attr(feature = "wasm", derive(specta::Type))]
#[repr(transparent)]
pub struct AccountId(
    #[cfg_attr(feature = "wasm", specta(type = Brand<Uuid, "AccountId">))]
    Uuid,
);

Which reduces to:

export type AccountId = Brand<string>
export type AddAccountGroupMember = { accountGroupId: AccountGroupId; accountId: AccountId }
export type Brand<T> = { _marker: null }

Now, this is not ideal due to several factors:

  1. need to remove export Type Brand<T>
  2. need to manually add import header for import {Brand} from ts-brand; (not that bad)
  3. needs nightly support for adt_const_params, which is incomplete.
  4. The const parameter is not carried over.

What I would love (in a perfect world) would be something similar to:

import {Brand} from 'ts-brand';

export type Uuid = Brand<Uuid, 'Uuid'>
export type AccountId = Brand<Uuid, 'AccountId'>
export type AddAccountGroupMember = { accountGroupId: AccountGroupId; accountId: AccountId }

How would I approach this problem? Any help would be greatly appreciated!

@oscartbeaumont
Copy link
Owner

The const parameter is not carried over.

Tracked in #17. I intend to support this in Specta v2 (mostly to avoid the need for Specta v3) but it's worth noting Serde doesn't support const parameters.

need to remove export Type Brand

It's hacky but this is possible (and sadly is something we do in Spacedrive).

If you're using 2.0.0-rc.x releases you will need to use main for (cab26b1) or if your using the crates.io releases the TypeMap (previously TypeDefs) was just a BTreeMap so you can do whatever.

Getting access to the TypeMap it's not super easy right now, you would need to copy the implementation of either specta::ts::export or specta::ts::inline into your own crate based on which one you are using.

This is the sorta feature that probably needs its own higher-level abstraction outside of the specta core crate.

need to manually add import header for import {Brand} from ts-brand; (not that bad)

Right now you would have to do this manually after Specta runs. Tauri Specta has a header propery which is set by the user and is injected at the start of the file. This is something Specta should probs have too which was an oversight.

I created #202 to track this

How would I approach this problem?

I'm honestly not sure we have a way to express this at the moment. It could be done with #110 or #17 but neither are supported at the moment and both have unanswered questions about exactly how I would want them to work.

@oscartbeaumont
Copy link
Owner

A correction to the bit about the header property only matters when using the export feature flag. The normal specta::ts::* stuff doesn't suffer that problem because it's on you to deal with the file writing.

@oscartbeaumont oscartbeaumont added the breaking change This will probs end up in the next major version. label Jan 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change This will probs end up in the next major version.
Projects
None yet
Development

No branches or pull requests

2 participants