Skip to content

feat(useDateFormat): add generic to return type #4719

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Kykydysik
Copy link

Before submitting the PR, please make sure you do the following

  • Read the Contributing Guidelines.
  • Read the Pull Request Guidelines.
  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • Ideally, include relevant tests that fail without this PR but pass with it.
⚠️ Slowing down new functions

Warning: Slowing down new functions

As the VueUse audience continues to grow, we have been inundated with an overwhelming number of feature requests and pull requests. As a result, maintaining the project has become increasingly challenging and has stretched our capacity to its limits. As such, in the near future, we may need to slow down our acceptance of new features and prioritize the stability and quality of existing functions. Please note that new features for VueUse may not be accepted at this time. If you have any new ideas, we suggest that you first incorporate them into your own codebase, iterate on them to suit your needs, and assess their generalizability. If you strongly believe that your ideas are beneficial to the community, you may submit a pull request along with your use cases, and we would be happy to review and discuss them. Thank you for your understanding.


Description

Additional context

@dosubot dosubot bot added the size:XS This PR changes 0-9 lines, ignoring generated files. label Apr 21, 2025
@ilyaliao
Copy link
Member

Can you explain a bit more about when generics are needed? Thanks.

@Kykydysik
Copy link
Author

@ilyaliao Hi, I added generic for better compatibility with other libraries. In particular, I work with primevue and I take some components (for example, datepicker) as the first argument (modelValue) Date and not string, but format as the second argument, which actually equates Date to string. I understand that this sounds like a primevue problem, but I'm sure that primevue is not the only library that works on a similar principle, so it's easier and more beautiful to add generic to vueuse.&

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Apr 22, 2025
Copy link
Collaborator

@OrbisK OrbisK left a comment

Choose a reason for hiding this comment

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

meant to request changes, not approve 🫠

@dosubot dosubot bot removed the lgtm This PR has been approved by a maintainer label Apr 22, 2025
Co-authored-by: Robin <robin.kehl@singular-it.de>
@ilyaliao
Copy link
Member

ilyaliao commented Apr 22, 2025

Making it generic could add some flexibility here, and I don’t think it’d be a breaking change.

maybe I’m missing something. @OrbisK @43081j wdyt?

@43081j
Copy link
Collaborator

43081j commented Apr 22, 2025

i'd like to see an example of the usage that lead to this

e.g. you say you bump into it in primevue. can you show us?

formatDate will always return a string, so what case is there where it'd give us something we can type any stronger than that? a string literal type? if so, how?

@Kykydysik
Copy link
Author

Kykydysik commented Apr 22, 2025

@43081j Please look at this primevue file. on 519 line you can see that modelValue has type Date | Array<Date> | Array<Date | null> | undefined | null;.
So if i do stuff like:

const localDate = ref<DatePickerProps['modelValue']>(null);
localDate.value = useDateFormat(new Date()); // here will be error Vue: Type ComputedRef<string> is not assignable to type DatePickerProps['modelValue']

<DatePicker
        :model-value="localDate"
      />

@43081j
Copy link
Collaborator

43081j commented Apr 22, 2025

the type error is right, though.

useDateFormat resolves to a string, not a Date

you would need to turn it back into a Date or change your value to accept strings

@Kykydysik
Copy link
Author

Yes, i undertstand this but i think a code like this
localDate.value = useDateFormat<Date>(new Date());
would look more beautiful.

@43081j
Copy link
Collaborator

43081j commented Apr 22, 2025

it would be an error, though:

localDate.value; // Date | Date[]

useDateFormat(new Date()); // string

localDate.value = useDateFormat(new Date()); // type error, we're trying to assign a string to a Date

your change here is to define the return type of useDateFormat. but the return type is always a string, so it doesn't make much sense to pretend it is anything else, in fact that'd cover up errors.

when you write useDateFormat<Date>(val) what do you think Date is being used for? it can't be the return type, because we know this is always a string

Copy link
Collaborator

@OrbisK OrbisK left a comment

Choose a reason for hiding this comment

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

I think there is still a use case for this generic. But the return should extend a string.

Example:

type Month = "jan" | "feb" ...

const month = useDateFormat<Month>(useNow(), 'MMM')

@@ -119,6 +119,6 @@ export type UseDateFormatReturn = ComputedRef<string>
* @param formatStr - The combination of tokens to format the date
* @param options - UseDateFormatOptions
*/
export function useDateFormat(date: MaybeRefOrGetter<DateLike>, formatStr: MaybeRefOrGetter<string> = 'HH:mm:ss', options: UseDateFormatOptions = {}): UseDateFormatReturn {
export function useDateFormat<T = string>(date: MaybeRefOrGetter<DateLike>, formatStr: MaybeRefOrGetter<string> = 'HH:mm:ss', options: UseDateFormatOptions = {}): UseDateFormatReturn<T> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
export function useDateFormat<T = string>(date: MaybeRefOrGetter<DateLike>, formatStr: MaybeRefOrGetter<string> = 'HH:mm:ss', options: UseDateFormatOptions = {}): UseDateFormatReturn<T> {
export function useDateFormat<T extends string = string>(date: MaybeRefOrGetter<DateLike>, formatStr: MaybeRefOrGetter<string> = 'HH:mm:ss', options: UseDateFormatOptions = {}): UseDateFormatReturn<T> {

@@ -109,7 +109,7 @@ export function normalizeDate(date: DateLike) {
return new Date(date)
}

export type UseDateFormatReturn = ComputedRef<string>
export type UseDateFormatReturn<T = string> = ComputedRef<T>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
export type UseDateFormatReturn<T = string> = ComputedRef<T>
export type UseDateFormatReturn<T extends string = string> = ComputedRef<T>

@43081j
Copy link
Collaborator

43081j commented Apr 24, 2025

I don't think that's what the OP was trying to do though 😬 so it's likely this can be closed once there's understanding why it doesn't make sense to do the change

@OrbisK
Copy link
Collaborator

OrbisK commented Apr 24, 2025

I don't think that's what the OP was trying to do though

Yes, but with extends string this can still be a good addition to allow fine-tuning of the type, while still not allowing Date as a type.

@43081j
Copy link
Collaborator

43081j commented Apr 24, 2025

i dont think we would achieve that through a type parameter

it would be an overload:

function formatDate(date: Date, formatStr: "MMM", options: UseDateFormatOptions = {}): Month;
function formatDate(date: Date, formatStr: string, options: UseDateFormatOptions = {}): string;

but that is way off on a tangent for this PR. we should open a separate PR for that, if we even bother (as the only format you can strongly type is the month name, so doesn't seem worth it).

what this PR exists for and what the OP originally wanted, i think was a misunderstanding. but lets wait for a response

they specifically said useDateFormat<Date>(...) which doesn't make sense, as useDateFormat always returns a string. so this PR doesn't seem to make sense. @Kykydysik can you take a look at my explanation further up and let us know

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size:XS This PR changes 0-9 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants