Keep type name when using generic

I'm using a custom set of branding utilities (from ts-brand iirc).
export declare type AnyBrand = Brand<unknown, any>;

export declare type Brand<Base, Branding, ReservedName extends string = "__type__"> = Base & {
[K in ReservedName]: Branding;
} & {
__witness__: Base;
};
export declare type AnyBrand = Brand<unknown, any>;

export declare type Brand<Base, Branding, ReservedName extends string = "__type__"> = Base & {
[K in ReservedName]: Branding;
} & {
__witness__: Base;
};
Since I'm not using arktype's branding, I've made this (maybe not so great) function:
export function customArktypeBrand<TBrand extends AnyBrand>(validation: Type<string | number>): Type<TBrand> {
return validation as unknown as Type<TBrand>;
}

const schema = type({
id: customArktypeBrand<MyBrand>(type.number)
})
export function customArktypeBrand<TBrand extends AnyBrand>(validation: Type<string | number>): Type<TBrand> {
return validation as unknown as Type<TBrand>;
}

const schema = type({
id: customArktypeBrand<MyBrand>(type.number)
})
This works well enough so its not my main question, though if theres a better way lmk. I'm now wanting to pass a given brand to another type generically:
export const TranslationSchema = <T extends AnyBrand>(of: type.Any<T>) =>
type({
id: of,
value: "string",
});

const output = TranslationSchema(customArktypeBrand<MyBrand>(type.number));
type Output= typeof output.infer;
export const TranslationSchema = <T extends AnyBrand>(of: type.Any<T>) =>
type({
id: of,
value: "string",
});

const output = TranslationSchema(customArktypeBrand<MyBrand>(type.number));
type Output= typeof output.infer;
This works, but now the output type is inferred like:
type Test = {
id: {
__type__: "myBrand";
} & {
__witness__: number;
};
value: string;
}
type Test = {
id: {
__type__: "myBrand";
} & {
__witness__: number;
};
value: string;
}
Which isn't ideal since I'm exporting from a package this and want it to instead be:
type Test = {
id: MyBrand;
value: string;
}
type Test = {
id: MyBrand;
value: string;
}
2 Replies
Bobakanoosh
BobakanooshOP2mo ago
I tried this example:
export const TranslationSchema = <const def>(
of: type.validate<def>
): type.instantiate<{ id: def; value: string }> =>
type.raw({
id: of,
value: "string",
}) as never;

const Test = TranslationSchema(customArktypeBrand<SiegeOperatorNameId>(type.number));
type Test = typeof Test.infer;
export const TranslationSchema = <const def>(
of: type.validate<def>
): type.instantiate<{ id: def; value: string }> =>
type.raw({
id: of,
value: "string",
}) as never;

const Test = TranslationSchema(customArktypeBrand<SiegeOperatorNameId>(type.number));
type Test = typeof Test.infer;
to no avail either, the inferred type of value becomes never. finally:
export const TranslationSchema = <T extends AnyBrand>(): Type<{ id: T; value: string }> =>
type({
id: "number",
value: "string",
}) as never;
export const TranslationSchema = <T extends AnyBrand>(): Type<{ id: T; value: string }> =>
type({
id: "number",
value: "string",
}) as never;
ssalbdivad
ssalbdivad2mo ago
Glad it's working for you! Can definitely be tricky to get those parameters inferred and passed along the way you want in TS

Did you find this page helpful?