vue-types icon indicating copy to clipboard operation
vue-types copied to clipboard

`oneOfType` and `oneOf` support generics

Open danranVm opened this issue 4 years ago • 7 comments

Using generics can help us better constraint types, likes:

type Genre = 'action' | 'thriller'

interface User {
  name: string
}

props: {
  genre: oneOf<Genre>(['action', 'thriller'])
  user: oneOfType<string | User>([String, object()])
}

danranVm avatar Jul 22 '21 03:07 danranVm

If you agree, I can provide a PR.

see: https://github.com/IduxFE/idux/blob/main/packages/cdk/utils/src/props.ts#L118

danranVm avatar Jul 22 '21 04:07 danranVm

Hi @danranVm, some work to implement type generics is undergoing in https://github.com/dwightjack/vue-types/pull/136 and other PRs referenced there. The latest changes have been published in [email protected].

If you need a fix for oneOfType right away staying on the stable version, you can already achieve the result in your example in a less elegant way:

user: oneOfType([String, object<User>()])

For oneOf I don't plan to add generics at the moment because you can more easily do the same by using a const assertion:

genre: oneOf(['action', 'thriller'] as const)

dwightjack avatar Jul 22 '21 12:07 dwightjack

user: oneOfType([String, object<User>()])
genre: oneOf(['action', 'thriller'] as const)

Hi @dwightjack , thanks for your answer, I know both of these schemes. They work well in most cases, but there are some things that are not friendly. E.g:

// If the non-displayed declaration is null, the type of footer cannot be deduced correctly
footer: oneOfType<any[] | VNode | null>([array(), vNode])
// spelling errors 😭, of course, this is not a problem with `vue-types`, but I want to avoid this problem as much as possible.
genre: oneOf(['action', 'thriler'] as const)

danranVm avatar Jul 23 '21 06:07 danranVm

@danranVm [email protected] already supports type arguments for the oneOfType validator. You can try it out right away. As a side note, I'd avoid using null as a prop type in Vue because the framework doesn't really support nullable props even if they might work after all.

As for oneOf, I am not an expert in generics, but I'd like to understand the changes required to make it work.

I have created a branch named ts-args-for-oneof with experimental support: https://github.com/dwightjack/vue-types/compare/ts-args-for-natives...ts-args-for-oneof?expand=1

As you can see from the examples, I created the following scenarios:

// 1
export const oneOfTuple = oneOf<1 | 2 | 'string'>([1, 'string'] as const).def(2) 
// 2
export const oneOfTuple2 = oneOf<1 | 2 | 'string'>([1, 2, 'string']).def(1) 
// 3
export const oneOfTuple3 = oneOf([1, 2, 'string'] as const).def(1)

I couldn't fix scenario 1, where there should be an error because the array does not include 2 as defined in the union type.

Any idea?

(also tagging @victorgarciaesgi because this discussion is related to https://github.com/dwightjack/vue-types/issues/140)

dwightjack avatar Jul 26 '21 08:07 dwightjack

I will look into this when I have time @dwightjack no problem! 😄

victorgarciaesgi avatar Jul 26 '21 12:07 victorgarciaesgi

@victorgarciaesgi thanks for your support. for now, I was asking your opinion on the feature, since we are working on these kind of features as well. I don't want you to feel pressed to work on it.

dwightjack avatar Jul 26 '21 14:07 dwightjack

After some research, I am not sure that there's a way to fix the issue in https://github.com/dwightjack/vue-types/issues/147#issuecomment-886476610 (I guess that's the nature of the union type, it cannot force the presence of a value).

For now, I have created a Draft PR with the related changes (https://github.com/dwightjack/vue-types/pull/151). I am not yet fully positive about it: while it helps with typos in the validation array, it allows scenarios with runtime errors not detected by the type checker like:

oneOf<1 | 2 | 'string'>([1, 'string'] as const).def(2)  // <-- at runtime this fails

dwightjack avatar Jul 28 '21 06:07 dwightjack

Support for union types in oneOf has been added in version 5 and is now available in [email protected].

Reference:

  • https://github.com/dwightjack/vue-types/pull/286

dwightjack avatar Nov 22 '22 08:11 dwightjack