Issue
I built a Generic Type for sort options. Now I am left with two alternatives, which both seem right.
// Option 1
export type SortSearchBy<DtoType> = Record<keyof Partial<Omit<DtoType, 'orderByFields'>>, SortBy>
// Option 2
export type SortSearchBy2<DtoType> = {
[x in keyof Partial<Omit<DtoType, 'orderByFields'>>]: SortBy
}
However the fields of DtoType
are only optional in the second option. For the first option, all fields of DtoType
(execpt for orderByOption
) have to be filled:
class AnimalDto {
name: string
age: number
orderByFields: SortSearchBy<AnimalDto>
}
// here you can('t) set
orderByOptions = {
name: {
option: 'ASC',
order: 1
},
// Error: Type is missing the following properties... (age)
}
class PersonDto {
name: string
age: number
orderByFields: SortSearchBy2<PersonDto> // Notice the 2
}
// while here it is possible
orderByFields = {
name: {
option: 'ASC',
order: 1
}
// No Error
}
Why does this behave differently, when I have used the Partial
generic for both types.
Solution
Solution
You are probably not looking for keyof Partial<Omit<DtoType, 'orderByFields'>>
you probably want:
export type SortSearchBy<DtoType> = Partial<Record<keyof Omit<DtoType, 'orderByFields'>, SortBy>>
Reason
Generally keyof T
and keyof Partial<T>
should be the same union of key. After all keyof
just returns the keys of a type regardless of the optionality of the properties.
While the statement above is generally true, mapped types have a special behavior. If you map over keyof T
(ie you have a type like { [P in keyof T]: U }
) where T
is any object type, the mapped type will turn homomorphic, meaning it will preserve the structure (optionality, readonly modifier) of the type T
you are mapping over.
So { [P in keyof Partial<Omit<DtoType, 'orderByFields'>>]: SortBy }
will be a homomorphic mapped type and it will preserve the structure of the type you are mapping. This means the properties in the resulting type will be optional since Partial<Omit<DtoType, 'orderByFields'>>
has all its properties marked as optional
In Record<keyof Partial<Omit<DtoType, 'orderByFields'>>, SortBy>
the mapping happens in Record
and it has no knowledge of were the keys it's mapping over came from, as the keyof
happens before Record
gets a hold of the keys.
Answered By - Titian Cernicova-Dragomir
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.