typescript - Cum să elimini cheile de tip `never`?


Am creat acest tip de utilitate numit Override pe care îl consider destul de util, dar un lucru care m-a deranjat este că nu este foarte convenabil să elimini complet proprietățile remove.

În exemplul de mai jos, vreau ca Bar să păstreze a din Foo, să suprascrie b pentru a fi un string în loc de un number și să elimine c. Totuși, c rămâne, doar că este tipizat ca never. Cum pot să elimin toate valorile de tip never în schimb?

type Override<A, B> = Omit<A, keyof B> & B

type Foo = {
    a: string
    b: number
    c: boolean
}

type Bar = Override<Foo, {
    b: string
    c: never
}>

function f(bar: Bar) {
   console.log(bar.c)
}

Teren de joacă

Răspuns #1

În loc de & B, poți să faci intersecția cu o mapare a unui tip de obiect nou din care au fost eliminate valorile never.

type Override<A, B> = Omit<A, keyof B> & {
    [K in keyof B as B[K] extends never ? never : K]: B[K]
}

Acest lucru poate fi extins pentru a elimina orice tip de valoare doriți.

type Override<A, B> = Omit<A, keyof B> & {
    [K in keyof B as B[K] extends never | void ? never : K]: B[K]
}

Răspunsul #2

am găsit o problemă similară https://github.com/microsoft/TypeScript/issues/23199

type Override<A, B> = Omit<A, keyof B> & B

type Foo = {
  a: string
  b: number
  c: boolean
}

type FilteredKeys<T> = {
  // this does not work
  // [K in keyof T]: K

  // this do
  [K in keyof T]: T[K] extends never ? never : K
}[keyof T]

type RemoveNever<T> = {
  [K in FilteredKeys<T>]: T[K]
}

type Bar = RemoveNever<
  Override<
    Foo,
    {
      b: string
      c: never
      d: number
    }
  >
>

function f(bar: Bar) {
  console.log(bar.a)
  console.log(bar.b)
  console.log(bar.c)
  console.log(bar.d)
}

Apropo, credem că aceste două forme sunt aceleași, dar tsc nu crede

  • [K in keyof T]: K
  • [K in keyof T]: T[K] extends never ? never : K