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
never
via 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
.