我正在尝试找到一种方法来从函数重载中获得严格的参数区分。显然,我的这个实现的问题是我的通用类型 T
可以扩展到任何继承AorB
的东西props 所以我在这里得到的错误是完全可以预料的( '{ type: "A"; a: any; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'AorB'.
)。
我正在寻找的是一种拥有某种 <T implements AorB>
的方法这样当参数 type
等于 "A"
,customProps
参数被判别为A
Prop 。
我也试图避免使用 any
在函数实现参数或as
内在返回之内。
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')
更新
如果我强制执行AorB
作为返回值:
function createAorB<T extends AorB>(type: T['type'], customProps: Partial<Omit<T, 'type'>> = {}): AorB
我收到两个错误 Property 'a' does not exist on type 'Partial<Omit<T, "type">>'.
和Property 'b' does not exist on type 'Partial<Omit<T, "type">>'.
分别在customProps.a
和customProps.b
行。
最佳答案
参数列表tuple type的createAOrB()
形成 discriminated union ,其中第一个元组元素是判别式。它看起来像这样:
type Args =
[type: "A", customProps?: Partial<Omit<A, "type">>] |
[type: "B", customProps?: Partial<Omit<B, "type">>];
如果您使用 rest parameter和 destructuring assignment将元素分配给名为 type
的变量和customProps
,您可以annotate其余参数为Args
,然后 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
}
}
如果 AorB
中碰巧有很多类型不仅仅是A | B
,扩展 Args
可能会很乏味。定义。在这种情况下,您可以让编译器将其计算为 AorB
的函数。 ,像这样:
type Args = AorB extends infer T ? T extends AorB ? (
[type: T['type'], customProps?: Partial<Omit<T, 'type'>>]
) : never : never;
这使用 conditional type inference复制AorB
进入新的generic类型参数T
,然后用它来制作 distributive conditional type这样[type: T['type'], customProps?: Partial<Omit<T, 'type'>>]
自动变成union type如果T
是联合类型(它分配 T
中联合的操作)。
您可以验证它的计算结果是否与上面手动定义的版本相同。
关于typescript - 如何使函数重载通用以强类型化其实现参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72747133/