TS - 类型 - 在保留类型的同时省略函数中参数对象中的字段

TS - types - omit field in parameter object in function while keeping types

我有一个类型可以省略函数参数对象中的指定字段,如下所示:

type OmitFields<F, K extends string> = F extends (props: infer P) => infer R ? (props: Omit<P, K>) => R : never;

并像这样使用它:

type Omitted = OmitFields<typeof functionWithObjectParam, 'first' | 'second'>

如何让类型参数 K 知道 props 对象被推断为的类型,并将正确的字符串限制为其键?

我想你想要这样的东西:

type OmitFields<
    F extends (props: any) => any,
    K extends keyof Parameters<F>[0],
> = (props: Omit<Parameters<F>[0], K>) => ReturnType<F>

这里 F 被限制为一个接受一个参数的函数。 K 受限于该参数的键。

然后你就可以重建函数类型而不需要任何花哨的东西infer

这似乎是你想要的:

function functionWithObjectParam(props: { a: number, b: number }) {}

type Omitted = OmitFields<typeof functionWithObjectParam, 'b'> // ok
type OmittedBad = OmitFields<typeof functionWithObjectParam, 'bad'> // Type '"bad"' does not satisfy the constraint '"b" | "a"'.(2344)

declare const fn: Omitted

fn({ a: 1 }) // ok

fn({ a: 1, b: 2 })
// Argument of type '{ a: number; b: number; }' is not assignable to parameter of type 'Omit<{ a: number; b: number; }, "b">'.
//   Object literal may only specify known properties, and 'b' does not exist in type 'Omit<{ a: number; b: number; }, "b">'.

Playground

您可以使用 TypeScript 实用程序类型 Parameters 而不是推断 F 函数第一个参数的类型 (props)。

Constructs a tuple type from the types used in the parameters of a function type Type.

从那里,您可以直接更具体地约束您的 K 泛型,而不仅仅是 extends string:例如 K extends keyof Parameters<F>[0]

现在为了更接近你的例子,我们可以让 F 可以是函数以外的东西,在这种情况下条件稍微复杂一些,但仍然 do-able:

type OmitFields<
  F,
  K extends (
    F extends (...args: any) => any
      ? keyof Parameters<F>[0]
      : string
  )
> = F extends (...args: any) => infer R
  ? (props: Omit<Parameters<F>[0], K>) => R
  : never;

declare function functionWithObjectParam(props: { key1: number; second: boolean; }): string;

type Omitted = OmitFields<typeof functionWithObjectParam, 'first' | 'second'>
  // TS2344 Type '"first" | "second"' does not satisfy the constraint '"second" | "key1"'. Type '"first"' is not assignable to type '"second" | "key1"'.

type Omitted2 = OmitFields<typeof functionWithObjectParam, 'key1' | 'second'> // Okay

type Omitted3 = OmitFields<string, 'first' | 'second'> // Okay

但是我怀疑在你的情况下条件类型只是为了启用类型推断。如果你有一个只接受函数的类型,它就会变得简单得多:

type OmitFields2<
  F extends (...args: any) => any,
  K extends keyof Parameters<F>[0]
> = (props: Omit<Parameters<F>[0], K>) => ReturnType<F>

type Omitted4 = OmitFields2<typeof functionWithObjectParam, 'first' | 'second'>
  // TS2344 Type '"first" | "second"' does not satisfy the constraint '"second" | "key1"'.

type Omitted5 = OmitFields2<typeof functionWithObjectParam, 'key1' | 'second'> // Okay

type Omitted6 = OmitFields2<string, 'first' | 'second'>
  // TS2344 Type 'string' does not satisfy the constraint '(...args: any) => any'.

Demo