Is it possible somehow to omit all never types from a type in typescript? I have a type that takes two other types, and based on values, generates a third type, and sets all incorrectly or differently valued elements to never:
type MapForeignKeys<TExpandMap extends expandMap, TForeignKeys> = {
[Prop in keyof TExpandMap]:
TExpandMap[Prop] extends { association: 'belongsTo', instance: BaseModel, foreignKey: any }
? TExpandMap[Prop]['instance']['_creationAttributes'] | TExpandMap[Prop]['instance'] | TForeignKeys[TExpandMap[Prop]['foreignKey']]
: never
}
When I try to use this type, the output contains properties that should be set to never, instead of omitting those types from the type definition, thus this becomes unusable.
A simple example that describes my problem can be found in this playground link
EDIT: A new link with some reproductible example of the problem
CodePudding user response:
One of the possible ways to omit keys is using as clause in mapped types.
You can filter out keys by producing
nevervia a conditional type
type OmitNever<T> = { [K in keyof T as T[K] extends never ? never : K]: T[K] }
So here we're replacing keys having never value with never keys and eventually they are omitted.
CodePudding user response:
Consider this example:
type WithNever = {
a: string
b: never
}
type Values<T> = T[keyof T]
type OmitNever<T> = Pick<T, Values<{
[Prop in keyof T]: [T[Prop]] extends [never] ? never : Prop
}>>
type Result = OmitNever<WithNever>
const test: OmitNever<WithNever> = {
a: 'test'
}; // ok
OmitNever - iterates through each key and checks whether it is never or not. If it is never leave it as is otherwise replace value type with key name.
Then Values obtains union of all produced values. Keep in mind that we ended up with object where each value is a result of conditional type.
If we have a union with never like "a" | never, TS will remove never and leave only a. Because of this, Values returns a union of all valid keys.
And a last step, we just use Pick with union of all valid keys
If you are wonder why I have used square brackets here [T[Prop]] extends [never] - please see this answer
UPDATE
// type Test = {
// [x: string]: never;
// foreignObject: string | number;
// manyObject: never;
// }
type Test = MapForeignKeys<expands, foreignKeys>
Are you sure that MapForeignKeys works as expected ? Because it returns and indexed object where each value expected to be never.
