我有一个函数,它返回一个具有相同形状的对象,除了一个可以命名为
value
defaultValue
,以价值为准
valueProp
. 下面是一个简单的例子:
type ValueType = 'value' | 'defaultValue'
function props0(valueProp: ValueType) {
return {
[valueProp]: 'value',
other: 'other',
}
}
任何一个
{value, other}
或
{defaultValue, other}
function expectsDefaultValue({defaultValue, other}) {
console.log('defaultValue:', defaultValue)
}
expectsDefaultValue(props0('defaultValue'))
,它抱怨我试图传递的值是
{ [x: string]: string; other: string; }
而不是预期/期望的类型,
{默认值,其他}
:
Argument of type '{ [x: string]: string; other: string; }' is not assignable to parameter of type '{ defaultValue: any; other: any; }'.
Property 'defaultValue' is missing in type '{ [x: string]: string; other: string; }' but required in type '{ defaultValue: any; other: any; }'.ts(2345)
使用索引类型?
index type
. 有什么方法可以将索引类型缩小到预期的类型吗?
看来我至少应该能
type assertion
告诉
字体说明它实际上是正确的形状,但是没有。。。
expectsDefaultValue(props0('defaultValue') as PropsUsingDefaultValue)
// => Conversion of type '{ [x: string]: string; other: string; }' to type
// 'PropsUsingDefaultValue' may be a mistake because neither type sufficiently
// overlaps with the other. If this was intentional, convert the expression to
// 'unknown' first.
// Property 'defaultValue' is missing in type '{ [x: string]: string; other:
// string; }' but required in type 'PropsUsingDefaultValue'.
这种索引类型一直存在同样的老问题。“强迫”的唯一方法似乎是这样,这似乎是不可接受的,这就是为什么我在这里寻找更好的解决方案:
expectsDefaultValue(props0('defaultValue') as unknown as PropsUsingDefaultValue)
不使用索引类型?
如果索引类型有太多限制(键只能是
string
ValueType
)...
如何使此函数通用
索引类型,并且没有任何额外的重复?
我的下一个尝试是使用
if/else
分支以显式返回形状正确的对象,但这太冗长,重复次数太多,不可接受:
interface Props {
other: any
}
interface PropsUsingValue extends Props {
value: any
other: any
}
interface PropsUsingDefaultValue extends Props {
defaultValue: any
other: any
}
function props1(valueProp: ValueType): PropsUsingValue | PropsUsingDefaultValue {
if (valueProp === 'value') {
return {
value: 'value',
other: 'other',
} as PropsUsingValue
} else {
return {
defaultValue: 'value',
other: 'other',
} as PropsUsingDefaultValue
}
}
即使这样我也不能这么做:
expectsDefaultValue(props1('defaultValue'))
// => Property 'defaultValue' is missing in type 'PropsUsingValue' but
// required in type 'PropsUsingDefaultValue'.ts(2345)
(为什么不在这里推断正确的、特定的返回值类型?)
但可以做到:
expectsDefaultValue(props1('defaultValue') as PropsUsingDefaultValue)
PropsUsingValue | PropsUsingDefaultValue
)把这里的字体弄混了(或者我遗漏了别的什么。。。?
也许有办法用
conditional types
为了说明我们只返回其中一种类型而不是那些类型的并集?
function props2<VT extends ValueType>(valueProp: VT):
VT extends 'value' ? PropsUsingValue : PropsUsingDefaultValue
{
if (valueProp === 'value') {
return {
value: 'value',
other: 'other',
} as PropsUsingValue
// => Type 'PropsUsingValue' is not assignable to type 'VT extends "value" ? PropsUsingValue : PropsUsingDefaultValue'.ts(2322)
} else {
return {
defaultValue: 'value',
other: 'other',
} as PropsUsingDefaultValue
}
}
映射类型?
因为索引类型似乎有限制(键只能是
一串
number
),也许我们可以尝试映射类型?(但具体如何?)
泛型的局限性?
好像我在做类似的事情
https://github.com/microsoft/TypeScript/issues/13995#issuecomment-463445339
,但显然泛型有一个限制,泛型扩展联合(它
值类型
我们如何解决这个限制(或者重写以避免遇到它)?
使用helper函数推断实际类型
this
也许 吧?
类型之间的映射表?
Narrowing a return type from a generic, discriminated union in TypeScript
也许我下一步会试试。