Home > Back-end >  Append generics with Omit in TypeScript
Append generics with Omit in TypeScript

Time:06-23

I am trying to set default properties using Omit<> in typescript and append more via generics.

For example, I want to exclude a set of properties by default and have the user choose more to exclude by using Omit<>

type OmittedEntity<TEntity extends IBaseEntity, TExtraOmissions extends (keyof TEntity) | void = void> = TExtraOmissions extends keyof TEntity ? Omit<TEntity, "id" | "collection" | TExtraOmissions> : Omit<TEntity, "id" | "collection">

interface IBaseEntity {
    id: string;
    collection: string;
    status: string;
}

// My new Entity
interface ISomeEntity extends IBaseEntity {
    firstName: string;
    lastName: string;
    middle: string;
}

When trying to exclude one more property than OmittedEntity<> does, every works perfectly

const e: OmittedEntity<ISomeEntity, "firstName"> = {
    lastName: "",
    middle: "",
    status: ""
}

When trying to exclude two or more properties than OmittedEntity<> does, I do not get the desired result. Typescript wants me to choose between omitting firstName or lastName

const e: OmittedEntity<ISomeEntity, "firstName" | "lastName"> = {
    lastName: "", // Error
    firstName: "", // Error
    middle: "",
    status: ""
}

How to I get the above example to allow me to exclude both properties, not one or the other?

I essentially want

const e: OmittedEntity<ISomeEntity, "firstName" | "lastName"> = {
    middle: "",
    status: ""
}

CodePudding user response:

You need to disable the distributivity of the conditional type.

type OmittedEntity<
  TEntity extends IBaseEntity, 
  TExtraOmissions extends (keyof TEntity) | void = void
> = [TExtraOmissions] extends [keyof TEntity] ? Omit<TEntity, "id" | "collection" | TExtraOmissions> : Omit<TEntity, "id" | "collection">

Without the square brackets, the elements in TExtraOmissions will be distributed to several Omits.

Playground


Also, you could simplify the whole OmmitedEntity type to this:

type OmittedEntity<
  TEntity extends IBaseEntity, 
  TExtraOmissions extends (keyof TEntity) = never
> = Omit<TEntity, "id" | "collection" | TExtraOmissions>

I don't see any benefit of using void here. We can just set the default to never, so if no type is given this will be ommitted from the union.

  • Related