有没有办法提示 TS 泛型参数的出现用于泛型推理?

kaz*_*vac 1 generics type-inference typescript

有没有办法提示 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;
Run Code Online (Sandbox Code Playgroud)

代码示例

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?
Run Code Online (Sandbox Code Playgroud)

ts 游乐场链接

jca*_*alz 6

您正在寻找microsoft/TypeScript#14829请求的功能,“非推理类型参数用法”:

通常,对于泛型,在某些位置应该可以从使用中推断出类型参数,而在其他位置,类型参数应该仅用于强制类型检查。这会在多种情况下出现。

那里的建议是提出一些NoInfer<T>语法,这相当于除了T编译器不会该位置推断之外T。这是您所要求的另一面,但它们都会实现相同的目标:属性类型NoInfer<T>上的ainput就像PleaseInfer<T>方法输入上的“” func()


虽然没有正式版本NoInfer<T>,但 GitHub 问题中提到了一些适用于某些用例的实现。 我有时推荐的一种是:

type NoInfer<T> = [T][T extends any ? 0 : never];
Run Code Online (Sandbox Code Playgroud)

当检查的类型是未解析的泛型时,这是通过利用编译器延迟计算分配条件类型来实现的。它无法“看到”NoInfer<T>将评估为T, 直到T是某种特定的已解析类型,例如在T推断之后。


有了这个,如果我将示例代码更改为:

type Handler = <T>(
  func: (params: Params<T>) => any,
  input: NoInfer<T>
) => string;
Run Code Online (Sandbox Code Playgroud)

然后您的示例将按预期工作:

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'
Run Code Online (Sandbox Code Playgroud)

Playground 代码链接