如何使类的泛型是必需的?

awe*_*eiu 5 typescript

班级是:

class Test<P> {
  constructor(data: P) {}
}
Run Code Online (Sandbox Code Playgroud)

我希望下面的代码没有通过类型检查,因为它没有传入的泛型:

new Test({ a: 1 })
Run Code Online (Sandbox Code Playgroud)

我知道上面的泛型 P 是自动派生为 的{a: number},但这不是我想要的,下面是。

new Test< {a: number} >({ a: 1 })
Run Code Online (Sandbox Code Playgroud)

我尝试了很多方法,但最终泛型 P 会自动派生到构造函数的参数类型中。

Tit*_*mir 7

有一个问题在这里处理非常相似的问题:

async function get<U = void>(url: string & (U extends void ? "You must provide a type parameter" : string)): Promise<U> {
    return null as any;
}
Run Code Online (Sandbox Code Playgroud)

不同之处在于,在那种情况下,参数中根本没有使用类型参数。这意味着打字稿没有地方推断它的类型参数。如果在您的情况下在参数列表中使用了类型参数,则打字稿将使用该参数作为来源来推断类型参数,并且我们使用默认值作为没有明确指定类型参数的信号的技巧将不会工作(因为打字稿不使用默认值,如果它可以推断类型参数)。

解决方案很简单,让 typescript 知道我们不希望它T从特定参数中推断出来。虽然没有内置支持来执行此操作,但 jcalz在这里提供了一个合理的解决方法

type NoInfer<T> = [T][T extends any ? 0 : never];
class Test<P = void> {
  constructor(data: NoInfer<P> & (P extends void ? "No type parameter was supplied" : {})) {}
}

new Test({ a: " "}) // err Argument of type '{ a: string; }' is not assignable to parameter of type 'void & "No type parameter was supplied"'.
new Test<{ a: string }>({ a: " "})// ok

Run Code Online (Sandbox Code Playgroud)


Tim*_*Tim 5

要更新 TypeScript 3.8.3,您可以简化此操作:

type NoInfer<T> = [T][T extends unknown ? 0 : never];

// Usage in a class:
class Test<P = "No type parameter was supplied"> {
  constructor(data: NoInfer<P>) {}
}

new Test({ a: " "}) // err Argument of type '{ a: string; }' is not assignable to parameter of type '"No type parameter was supplied"'.
new Test<{ a: string }>({ a: " "})// ok

// Usage in a function:
function Foo<P = "No type parameter was supplied"> (
  data: NoInfer<P>
) {
  return undefined
}
Run Code Online (Sandbox Code Playgroud)