Skip to content

Conversation

@andrewpeters9
Copy link

@andrewpeters9 andrewpeters9 commented Jan 13, 2026

Marking this as a draft, as it still requires more work & I was wanting input from the maintainers.

Idea:
Allow for the TS types of the newly (optionally) formatted IDs to narrow to prefix_{string} as opposed to just string:

type User = {
   // new behaviour
   id: `user_{string}`;
   // old behaviour
   id: string;
}

Motivations:

  • It provides a great level of granularity to type-safety, e.g.:
const fetchUser = (userId: User["id"]) => {
   // would ensure that no random strings can enter the function
}

Concerns:

  • will be a breaking change to people's types (but not their runtime), as some (like myself) may have already been using User["id"] with the assumption that it casts to a string
    • IMO, it would be a sane default, as most people that are prefixing their IDs are generally working in repos where type-safety is crucial
    • but if you disagree, we could potentially add a flag e.g. narrowType or something (defaults to false)
  • TS performance of these ternaries

@coderabbitai
Copy link

coderabbitai bot commented Jan 13, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment on lines 2 to 13
import type {
ExtractIdFormat,
FormatToTemplateLiteral,
MapStringWithFormat,
} from '../src/utils/type-utils';

describe('FormatToTemplateLiteral', () => {
it('converts simple prefix format to template literal', () => {
expectTypeOf<FormatToTemplateLiteral<'user_%s'>>().toEqualTypeOf<`user_${string}`>();
});
Copy link
Author

@andrewpeters9 andrewpeters9 Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is a bit verbose - let me know if you'd prefer me to trim it down

Comment on lines +319 to +325
//#region Field defaults

/**
* ID generator functions that support format strings (e.g., uuid(4, "user_%s"))
*/
export const ID_GENERATOR_FUNCTIONS = ['uuid', 'cuid', 'nanoid', 'ulid'] as const;
export type IdGeneratorFunction = (typeof ID_GENERATOR_FUNCTIONS)[number];
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't find a more appropriate file for this (but admittedly, seems very misplaced 😅)

Advise if you have another file in mind / or would prefer a new file

@andrewpeters9 andrewpeters9 force-pushed the feat/template-literal-id-types branch from 6aea088 to 54f8656 Compare January 13, 2026 07:57
@sanny-io
Copy link
Contributor

This would be a very cool feature. I hope everything works out in the end, because I do agree that this is a big improvement for safety. And I'm happy to see more improvements for ID formatting so quickly after its release :D

@andrewpeters9
Copy link
Author

andrewpeters9 commented Jan 14, 2026

This would be a very cool feature. I hope everything works out in the end, because I do agree that this is a big improvement for safety. And I'm happy to see more improvements for ID formatting so quickly after its release :D

Thanks for the feedback :)

Given you implemented this feature: do you think it should default to the narrower type of prefix_{string} or should it require an opt-in flag?

@sanny-io

@sanny-io
Copy link
Contributor

sanny-io commented Jan 14, 2026

@andrewpeters9 we are in a bit of a pickle at the moment because the format is not actually enforced at runtime. There's nothing stopping the user from inputting whatever ID they wanted, so the most appropriate type for the ID is indeed string, but I am of the opinion that users should not be able to do that, which is why I proposed #524.

If an ID field is readonly and has some inferable default value, then I think it should be narrowed. That makes the most sense to me because it maps 1-1 with const vs let in TypeScript. Whether that's feasible given the current constraints, I don't know.

@ymc9 ymc9 changed the base branch from main to dev January 15, 2026 03:16
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

Successfully merging this pull request may close these issues.

2 participants