tru*_*ktr 7 generics typescript
如何使通用模板类型参数成为必需?
到目前为止,我发现这样做的唯一方法是使用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()
Run Code Online (Sandbox Code Playgroud)
正如您在对 的调用中看到的test1(),错误发生在result.split('')因为never没有.split()方法。
在test2它的伟大工程时,我提供了通用的ARG。
我怎样才能使 arg 成为必需的,而不是从不使用,并且sendWorkRequest如果没有给出通用 arg,则在调用时发生错误?
请参阅此公开建议。我所知道的最好的方法是让T默认never为您所做的(假设这never不是 的有效类型参数T)并定义函数参数之一的类型,以便 (1) ifT指定为 non- never,则参数具有您实际想要的类型,并且 (2) 如果T允许默认为never,则该参数具有一些会生成错误的虚拟类型,因为它与参数类型不匹配。
棘手的部分是,如果调用者设置了它自己的T某个范围内类型变量U,我们希望允许调用,即使 TypeScript 不能排除U可能是never. 为了处理这种情况,我们使用了一个辅助类型IfDefinitelyNever,它滥用了索引访问类型的简化行为来区分确定never变量和类型变量。需要特殊的G(“gate”)参数来防止调用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()
Run Code Online (Sandbox Code Playgroud)
有一种更简单的方法可以实现上述目标,其中:
unknownasync 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();
}
Run Code Online (Sandbox Code Playgroud)
请参阅此 TypeScript 游乐场。
这是通过让 TypeScript 仅推断最后一个类型参数,同时将never非推断的主要类型参数设置为默认值来实现的。如果未传入显式类型参数,则会发生错误,因为传入的值不可分配给默认值never。至于返回类型,它是 的一个很好的用途unknown,因为除非明确参数化,否则它不会被推断为其他任何东西。
| 归档时间: |
|
| 查看次数: |
5678 次 |
| 最近记录: |