有没有办法提示 TS 泛型参数的出现用于泛型推理?
Is there a way to hint TS which occurrence of generic parameter to use for generic inference?
有没有办法提示 TS 泛型参数的出现用于泛型推理?
type Handler = <T>( // <-- if T is unspecified in method definition and call how can i tell ts to infer it to Ta from Params<Ta> and not Tb of the input?
func: (params: Params<Ta>) => any,
input: Tb
) => string;
代码示例
type Params<T = Record<string, unknown>> = {
p: T;
// other metadata
}
type Handler = <T>( // <-- if T is unspecified how can i tell ts to infer it from Params<T>?
func: (params: Params<T>) => any,
input: T
) => string;
type Config = {
handler: Handler
}
const c: Config = {
handler: (params, input) => 'ok' // <-- no possibility to pass/state the generic parameter here
}
type AB = {a:number, b:number}
const myHandler = (params: Params<AB>) => params.p.a + params.p.b;
c.handler(myHandler, { a:1, b:2, c:"unexpected" }) // <-- T is inferred to { a:1, b:2, c:"unexpected" }
c.handler<AB>(myHandler, { a:1, b:2, c:"unexpected" }) // <-- this is desired behaviour, can it be done without stating the T = AB explicitly?
可以通过改变类型来实现:
type Params<T = Record<string, unknown>> = {
p: T;
// other metadata
}
type ParamsExtract<T extends (params: Params<any>) => any> = T extends (params: Params<infer U>) => any ? U : never;
type Handler = <Fn extends (params: Params<any>) => any>( // <-- if T is unspecified how can i tell ts to infer it from Params<T>?
func: Fn,
input: ParamsExtract<Fn>
) => string;
type Config = {
handler: Handler
}
const c: Config = {
handler: (params, input) => 'ok' // <-- no possibility to pass/state the generic parameter here
}
type AB = {a:number, b:number}
const myHandler = (params: Params<AB>) => params.p.a + params.p.b;
c.handler(myHandler, { a:1, b:2, c:"unexpected" }) // error
因此泛型成为函数类型,并且从中提取参数。参见 here。
您正在寻找 microsoft/TypeScript#14829 请求的功能,“非推理类型参数用法”:
Often with generics, there will be some locations where a type parameter should be inferrable from usage, and other places where the type parameter should only be used to enforce typechecking. This comes up in a variety of contexts.
那里的提议是想出一些 NoInfer<T>
语法,这等同于 T
除了编译器会 不 推断 T
从那个位置。这是您要求的另一面,但它们都将实现相同的目标: input
属性 类型上的 NoInfer<T>
就像“PleaseInfer<T>
" 在 func()
方法的输入上。
虽然 NoInfer<T>
没有 官方 版本,但 GitHub 问题中提到的一些实现适用于某些用例。 One I sometimes recommend 是:
type NoInfer<T> = [T][T extends any ? 0 : never];
这是通过利用编译器 延迟 评估 distributive conditional types 当检查的类型是未解析的泛型时。它无法“看到”NoInfer<T>
将计算为 T
,直到 T
是某个特定的已解析类型,例如在推断出 T
之后。
有了这些,如果我将您的示例代码更改为:
type Handler = <T>(
func: (params: Params<T>) => any,
input: NoInfer<T>
) => string;
那么您的示例将按预期工作:
const c: Config = {
handler: (func, input) => func({ p: input }) // okay,
}
type AB = { a: number, b: number }
const myHandler = (params: Params<AB>) => params.p.a + params.p.b;
c.handler(myHandler, { a: 1, b: 2, c: "unexpected" }); // error!
// ------------------------------> ~~~~~~~~~~~~~~~
// Object literal may only specify known properties,
// and 'c' does not exist in type 'AB'
有没有办法提示 TS 泛型参数的出现用于泛型推理?
type Handler = <T>( // <-- if T is unspecified in method definition and call how can i tell ts to infer it to Ta from Params<Ta> and not Tb of the input?
func: (params: Params<Ta>) => any,
input: Tb
) => string;
代码示例
type Params<T = Record<string, unknown>> = {
p: T;
// other metadata
}
type Handler = <T>( // <-- if T is unspecified how can i tell ts to infer it from Params<T>?
func: (params: Params<T>) => any,
input: T
) => string;
type Config = {
handler: Handler
}
const c: Config = {
handler: (params, input) => 'ok' // <-- no possibility to pass/state the generic parameter here
}
type AB = {a:number, b:number}
const myHandler = (params: Params<AB>) => params.p.a + params.p.b;
c.handler(myHandler, { a:1, b:2, c:"unexpected" }) // <-- T is inferred to { a:1, b:2, c:"unexpected" }
c.handler<AB>(myHandler, { a:1, b:2, c:"unexpected" }) // <-- this is desired behaviour, can it be done without stating the T = AB explicitly?
可以通过改变类型来实现:
type Params<T = Record<string, unknown>> = {
p: T;
// other metadata
}
type ParamsExtract<T extends (params: Params<any>) => any> = T extends (params: Params<infer U>) => any ? U : never;
type Handler = <Fn extends (params: Params<any>) => any>( // <-- if T is unspecified how can i tell ts to infer it from Params<T>?
func: Fn,
input: ParamsExtract<Fn>
) => string;
type Config = {
handler: Handler
}
const c: Config = {
handler: (params, input) => 'ok' // <-- no possibility to pass/state the generic parameter here
}
type AB = {a:number, b:number}
const myHandler = (params: Params<AB>) => params.p.a + params.p.b;
c.handler(myHandler, { a:1, b:2, c:"unexpected" }) // error
因此泛型成为函数类型,并且从中提取参数。参见 here。
您正在寻找 microsoft/TypeScript#14829 请求的功能,“非推理类型参数用法”:
Often with generics, there will be some locations where a type parameter should be inferrable from usage, and other places where the type parameter should only be used to enforce typechecking. This comes up in a variety of contexts.
那里的提议是想出一些 NoInfer<T>
语法,这等同于 T
除了编译器会 不 推断 T
从那个位置。这是您要求的另一面,但它们都将实现相同的目标: input
属性 类型上的 NoInfer<T>
就像“PleaseInfer<T>
" 在 func()
方法的输入上。
虽然 NoInfer<T>
没有 官方 版本,但 GitHub 问题中提到的一些实现适用于某些用例。 One I sometimes recommend 是:
type NoInfer<T> = [T][T extends any ? 0 : never];
这是通过利用编译器 延迟 评估 distributive conditional types 当检查的类型是未解析的泛型时。它无法“看到”NoInfer<T>
将计算为 T
,直到 T
是某个特定的已解析类型,例如在推断出 T
之后。
有了这些,如果我将您的示例代码更改为:
type Handler = <T>(
func: (params: Params<T>) => any,
input: NoInfer<T>
) => string;
那么您的示例将按预期工作:
const c: Config = {
handler: (func, input) => func({ p: input }) // okay,
}
type AB = { a: number, b: number }
const myHandler = (params: Params<AB>) => params.p.a + params.p.b;
c.handler(myHandler, { a: 1, b: 2, c: "unexpected" }); // error!
// ------------------------------> ~~~~~~~~~~~~~~~
// Object literal may only specify known properties,
// and 'c' does not exist in type 'AB'