Home > database >  Omit never types in typescript
Omit never types in typescript

Time:11-05

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.

Playground

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

Playground

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.

  • Related