对于类型T(作为一组属性),如何创建类型V减去U,这是T的子集



我有一个接口Abcd,它有几个属性:

interface Abcd {
  a: string
  b: number
  c: boolean
  d: string
}

我想为作为参数传递给函数setOptions的对象定义一个类型Options。在options对象中,有两个属性:

  1. fn是一个异步回调,返回Abcd的属性子集
  2. remaining是一个包含返回类型fn中缺少的其余属性的对象

像这样:

setOptions<Abcd>({
  fn: async () => ({ a: "aaa" }),
  remaining: {
    b: 123,
    c: false,
    d: "ddd",
  }
})

是否可以确保,如果fn返回属性a,则remaining不应包含该属性?如果remainingfn的返回值中都缺少属性,则类型也应该抱怨。它应该拒绝额外的财产。

例如:

setOptions<Abcd>({
  fn: async () => ({ a: "aaa" }),
  remaining: { // error, missing property `d`
    a: "aaa", // error, `a` is already in the return type of `fn`
    b: "bbb", // error, type of `b` should be 'number'
    c: false,
    e: "extra prop", // error, `e` is not in `Abcd`
  }
})

我试过了:

interface Options<T extends object, U = Partial<T>, V = Omit<T, keyof U>> {
  fn: () => Promise<U>
  remaining: V
}
function setOptions<T extends object>(options: Options<T>) {
}

这是我最接近的尝试,但不是解决办法。

帮助:游乐场中的相同代码。

没有K的类型推断

interface Options<T extends object, K extends keyof T> {
  fn: () => Promise<Pick<T, K>>;
  remaining: Omit<T, K>
}
function setOptions<T extends object, K extends keyof T>(options: Options<T, K>) {}
interface Abcd {
  a: string
  b: number
  c: boolean
  d: string
}
setOptions<Abcd, 'a'>({
  fn: async () => ({ a: "aaa" }),
  remaining: {
    b: 123,
    c: false,
    d: "ddd",
  }
})

具有K的类型推断

你需要一个额外的函数调用:

const setOptions = <T extends object>() =>
  <K extends keyof T>(source: {
    fn: () => Promise<Pick<T, K>>;
    remaining: Omit<T, K>
  }) => { }
  
interface Abcd {
  a: string
  b: number
  c: boolean
  d: string
}
setOptions<Abcd>()({
  fn: async () => ({ a: '' }),
  remaining: {
    b: 1,
    c: false,
    d: "ddd",
  }
})

游乐场

最新更新