![](/img/trans.png)
[英]How to make Typescript infer a generic method argument type in an object
[英]How to make a generic type argument required in typescript?
如何使通用模板类型参数成为必需的?
到目前为止,我发现唯一的方法是使用never
但它会导致错误发生在泛型调用站点以外的其他地方。
此处粘贴的TypeScript 游乐场示例:
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,我如何才能使 arg 成为必需的,而不是从不使用,并且在调用sendWorkRequest
时发生错误?
请参阅此公开建议 。 我所知道的最好方法是让T
默认为never
不像您默认的那样(假设Never never
不是T
的有效类型参数)并定义函数参数之一的类型,以便(1)如果指定了T
作为non- never
,则参数具有您实际想要的类型,并且(2)如果允许T
默认为never
,则参数具有某种虚拟类型,因为它与参数类型不匹配,将产生错误。
棘手的部分是,如果调用者将T
设置为其自己的某个范围内类型变量U
,则即使TypeScript不能排除U
never
是T
,我们也希望允许调用。 为了处理这种情况,我们使用了一个辅助类型IfDefinitelyNever
,它滥用索引访问类型的简化行为来将一个确定的never
与类型变量区分开。 需要特殊的G
(“门”)参数,以防止来自IfDefinitelyNever
的调用在函数本身的签名中过早评估其假分支。
type RequestType =
| 'foo'
| 'bar'
| 'baz'
interface SomeRequest {
id: string
type: RequestType
sessionId: string
bucket: string
params: Array<any>
}
type ResponseResult = string | number | boolean
const ERROR_INTERFACE_DUMMY = Symbol();
interface Type_parameter_T_is_required {
[ERROR_INTERFACE_DUMMY]: never;
}
interface Do_not_mess_with_this_type_parameter {
[ERROR_INTERFACE_DUMMY]: never;
}
type IfDefinitelyNever<X, A, B, G extends Do_not_mess_with_this_type_parameter> =
("good" | G) extends {[P in keyof X]: "good"}[keyof X] ? B : ([X] extends [never] ? A : B);
async function sendWorkRequest<T extends ResponseResult = never,
G extends Do_not_mess_with_this_type_parameter = never>(
type: RequestType & IfDefinitelyNever<T, Type_parameter_T_is_required, unknown, G>,
...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() {
// Error: Argument of type '"foo"' is not assignable to parameter of type
// '("foo" & Type_parameter_T_is_required) |
// ("bar" & Type_parameter_T_is_required) |
// ("baz" & Type_parameter_T_is_required)'.
const result = await sendWorkRequest('foo')
result.split('')
}
test1()
// WORKS
async function test2() {
const result = await sendWorkRequest<string>('foo')
result.split('')
}
test2()
// ALSO WORKS
async function test3<U extends ResponseResult>() {
const result = await sendWorkRequest<U>('foo')
}
test3()
有一种更简单的方法可以实现上述目的,其中:
unknown
的值 async function sendWorkRequest<ReqT = never, ResT = unknown, InferredReqT extends ReqT = ReqT>(
request: InferredReqT,
): Promise<ResT> {
return {} as ResT;
}
// Call does not succeed without an explicit request parameter.
async function test1() {
const result = await sendWorkRequest('foo');
// ~~~~~
// ERROR: Argument of type '"foo"' is not assignable to parameter of type 'never'
}
// Call succeeds, but response is 'unknown'.
async function test2() {
const result: number = await sendWorkRequest<string>('foo');
// ~~~~~~
// ERROR: Type 'unknown' is not assignable to type 'number'.
result.valueOf();
}
// Call succeeds and returns expected response.
async function test3() {
const result = await sendWorkRequest<string, number>('foo');
result.valueOf();
}
看到这个TypeScript游乐场 。
这是通过让TypeScript仅推断出最后一个类型参数,而never
将其设置为非推断出的主类型参数的默认值而起作用的。 如果未传递显式类型参数,则会发生错误,因为传递的值不可分配给默认的never
。 至于返回类型,它极大地使用了unknown
,因为除非明确地对其进行参数化,否则它不会被推断为其他任何类型。
这就是我如何使我的第一个通用强制性
const fn = <T = never, AT extends T = T>(arg: AT): any => {}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.