如何使函数过载通用性强烈键入其实现参数?

发布于 2025-02-10 10:37:38 字数 1343 浏览 2 评论 0 原文

我正在尝试找到一种从功能过载中获得严格的参数歧视的方法。显然,我对此实施的问题是,我的通用类型 t 可以扩展到继承的任何 aorb props props,因此我在这里获得的错误是完全期望的('{type :“ a”:任何;

我正在寻找的是一种使某种< t实现aorb> 的方法>, customProps 参数被区分为 a props。

我还试图避免在函数实现参数中使用在返回中的中使用。

type A = {
  a: string
  type: 'A'
}

type B = {
  b: string
  type: 'B'
}

type AorB = A | B

function createAorB(type: A['type'], customProps?: Partial<Omit<A, 'type'>>): A
function createAorB(type: B['type'], customProps?: Partial<Omit<B, 'type'>>): B
function createAorB<T extends AorB>(type: T['type'], customProps: Partial<Omit<T, 'type'>> = {}): T {
  if (type === 'A') {
    return {
      type,
      a: customProps.a || '',
    }
  }

  return {
    type,
    b: customProps.b || '',
  }
}

const newA = createAorB('A')
const newB = createAorB('B')

update

如果我执行 aorb 作为返回值:

function createAorB<T extends AorB>(type: T['type'], customProps: Partial<Omit<T, 'type'>> = {}): AorB

我得到两个错误 propert'a''''''''''partial&lt; omit&lt; t; &gt;&gt;'。属性'b'在类型'partial&lt; omit&lt; t上,“ type”&gt;&gt;'。 .a customProps.b 行。

I'm trying to find a way to get a strict parameters discrimination from a function overload. Obviously my issue with this implementation is that my generic type T can be extended to anything inheriting AorB props so the error I get here is perfectly expected ('{ type: "A"; a: any; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'AorB'.).

What I'm looking for is a way to have a sort of <T implements AorB> so that when the parameter type equals "A", the customProps parameter is discriminated as A props.

I'm also trying to avoid resorting to use any within the function implementation parameters or as within the returns.

type A = {
  a: string
  type: 'A'
}

type B = {
  b: string
  type: 'B'
}

type AorB = A | B

function createAorB(type: A['type'], customProps?: Partial<Omit<A, 'type'>>): A
function createAorB(type: B['type'], customProps?: Partial<Omit<B, 'type'>>): B
function createAorB<T extends AorB>(type: T['type'], customProps: Partial<Omit<T, 'type'>> = {}): T {
  if (type === 'A') {
    return {
      type,
      a: customProps.a || '',
    }
  }

  return {
    type,
    b: customProps.b || '',
  }
}

const newA = createAorB('A')
const newB = createAorB('B')

UPDATE

If I enforce AorB as the return value:

function createAorB<T extends AorB>(type: T['type'], customProps: Partial<Omit<T, 'type'>> = {}): AorB

I get both errors Property 'a' does not exist on type 'Partial<Omit<T, "type">>'. and Property 'b' does not exist on type 'Partial<Omit<T, "type">>'. on the respective customProps.a and customProps.b lines.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

暮光沉寂 2025-02-17 10:37:38

参数列表 ()表格a ,其中第一个元组元素是判别。看起来像这样:

type Args = 
   [type: "A", customProps?: Partial<Omit<A, "type">>] | 
   [type: "B", customProps?: Partial<Omit<B, "type">>]; 

如果您使用 and 名为 type customprops 的变量的元素,您可以 norotate args args ,然后编译器将使用控制流程分析来缩小 ustomprops 检查类型

function createAorB(type: A['type'], customProps?: Partial<Omit<A, 'type'>>): A
function createAorB(type: B['type'], customProps?: Partial<Omit<B, 'type'>>): B
function createAorB(...[type, customProps]: Args) {
  if (type === 'A') {
    return {
      type,
      a: customProps?.a || '', // okay
    }
  }

  return {
    type,
    b: customProps?.b || '', // okay
  }
}

如果您碰巧在 aorb 中有很多类型,而不仅仅是 a | b ,扩展 args 定义可能很乏味。在这种情况下,您可以让编译器为您计算为 aorb 的函数,如以下:

type Args = AorB extends infer T ? T extends AorB ? (
  [type: T['type'], customProps?: Partial<Omit<T, 'type'>>]
) : never : never;

这使用条件类型推进将复制 aorb aorb /www.typescriptlang.org/docs/handbook/2/generics.html“ rel =” nofollow noreferrer“> generic type parameter t t ,然后用于使A 联合类型如果 t 是联合类型 t 中的工会的操作)。

您可以验证它的评估与上面的手动定义版本相同。

Playground link to code

The argument list tuple type of createAOrB() forms a discriminated union, where the first tuple element is the discriminant. It looks like this:

type Args = 
   [type: "A", customProps?: Partial<Omit<A, "type">>] | 
   [type: "B", customProps?: Partial<Omit<B, "type">>]; 

If you use a rest parameter and destructuring assignment to assign the elements to variables named type and customProps, you can annotate the rest parameter as Args, and then the compiler will use control flow analysis to narrow customProps when you check type:

function createAorB(type: A['type'], customProps?: Partial<Omit<A, 'type'>>): A
function createAorB(type: B['type'], customProps?: Partial<Omit<B, 'type'>>): B
function createAorB(...[type, customProps]: Args) {
  if (type === 'A') {
    return {
      type,
      a: customProps?.a || '', // okay
    }
  }

  return {
    type,
    b: customProps?.b || '', // okay
  }
}

If you happen to have lots of types in AorB and not just A | B, it might be tedious to extend the Args definition. In this case you can have the compiler compute it for you as a function of AorB, like this:

type Args = AorB extends infer T ? T extends AorB ? (
  [type: T['type'], customProps?: Partial<Omit<T, 'type'>>]
) : never : never;

This uses conditional type inference to copy AorB into a new generic type parameter T, which is then used to make a distributive conditional type so that [type: T['type'], customProps?: Partial<Omit<T, 'type'>>] automatically becomes a union type if T is a union type (it distributes the operation over unions in T).

You can verify that it evaluates to the same as the manually defined version above.

Playground link to code

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文