如何使泛型模板类型参数成为必需参数?
到目前为止,我找到的唯一方法是使用never
,但它会导致错误发生在泛型调用站点之外的其他位置。
将TypeScript Playground示例粘贴到此处:
type RequestType =
| 'foo'
| 'bar'
| 'baz'
interface SomeRequest {
id: string
type: RequestType
sessionId: string
bucket: string
params: Array<any>
}
type ResponseResult = string | number | boolean
async function sendWorkRequest<T extends ResponseResult = never>(
type: RequestType,
...params
): Promise<T> {
await this.readyDeferred.promise
const request: SomeRequest = {
id: 'abc',
bucket: 'bucket',
type,
sessionId: 'some session id',
params: [1,'two',3],
}
const p = new Promise<T>(() => {})
this.requests[request.id] = p
this.worker.postMessage(request)
return p
}
// DOESN'T WORK
async function test1() {
const result = await sendWorkRequest('foo')
result.split('')
}
test1()
// WORKS
async function test2() {
const result = await sendWorkRequest<string>('foo')
result.split('')
}
test2()
正如您在对test1()
的调用中看到的,错误发生在result.split('')
,因为never
没有.split()
方法。
在test2
中,当我提供泛型arg时,它工作得很好。
我怎样才能使arg成为必需的,而不是使用never,并且如果没有给出泛型arg,那么在调用sendWorkRequest
时会发生错误?
3条答案
按热度按时间tv6aics11#
有一种更简单的方法可以实现上述目的,其中:
1.必须提供显式类型形参才能无错误地传递实参,并且
1.必须提供第二个显式类型参数才能获取非
unknown
的值查看这个TypeScriptPlayground。
这是通过让TypeScript只推断最后一个类型参数,同时将
never
设置为非推断的主类型参数的默认值来实现的。如果没有传入显式类型参数,则会发生错误,因为传入的值不能赋给默认的never
。至于返回类型,这是unknown
的一个很好的用途,因为除非显式参数化,否则它不会被推断为其他任何东西。kmynzznz2#
我所知道的最好方法是让
T
默认为never
,就像您所做的那样(假设never
不是T
的有效类型参数),并定义函数的一个参数的类型,以便(1)如果T
被指定为non-never
,则参数具有您实际想要的类型,并且(2)如果T
被允许默认为never
,则参数具有将生成错误的某个伪类型,因为它与实参类型不匹配。棘手的是,如果调用者将
T
设置为它自己的某个范围内类型变量U
,那么即使TypeScript不能排除U
可能是never
,我们也希望允许该调用。我们使用助手类型X1 M12 N1 X,其滥用索引访问类型的简化行为来区分确定的X1 M13 N1 X和类型变量。需要特殊的G
(“gate”)参数来防止来自IfDefinitelyNever
的调用过早地计算到函数本身签名中的false分支。exdqitrt3#
这就是我如何使我的第一个通用强制