打字稿说我的对象缺少它不缺少的属性

Typescript says my object is missing properties that it isn't missing

我正在从事具有以下模式的项目:

interface IAuthProvider {
  middleware: () => void
  getInput: () => void
}

class Password implements IAuthProvider {
  middleware = () => {}
  getInput = () => {}
}

class Email implements IAuthProvider {
  middleware = () => {}
  getInput = () => {}
}

const providerNames = ['Email', 'Password']

type AuthProviderNamespace = { [K in typeof providerNames[number]]: IAuthProvider }

// error: Type 'typeof Password' is missing the following properties from type 'IAuthProvider': middleware, getInput
const providers: AuthProviderNamespace = { Email, Password }

我需要使用 AuthProviderNamespace 因为这种对象将被导入到一个模块中并直接传递给一个将迭代它的函数:

import * as AuthProviders from './providers/index.ts'

const providers = instantiateProviders(AuthProviders)

所以我需要输入 AuthProviders。但是我做错了一些事情,以至于打字稿无法将电子邮件和密码识别为 IAuthProvider 的实现者。我可以解决这个问题吗?

游乐场:https://tsplay.dev/wQV7jN

错误正确。值 {Email: Email, Password: Password} 是一个对象,其属性分别是 IAuthProvider 个对象的 个构造函数 。但是类型 {Email: IAuthProvider, Password: IAuthProvider} 对应的对象 EmailPassword 属性是 IAuthProvider 实例 ,而不是此类实例的构造函数。 class 构造函数 Email 没有 getInput 属性,因此它不能是 IAuthProvider:

Email.getInput; // <-- error, Property 'getInput' does not exist on type 'typeof Email'

假设您对 providers 的意图是使用其属性构造 IAuthProvider 的新实例,如下所示:

const provider = new providers.Email(); // note, assuming a no-arg constructor
provider.getInput(); // okay
provider.middleware(); // okay

然后您需要更改 AuthProviderNamespace 类型,使其属性是 IAuthProvider 实例的 no-arg 构造函数。您可以使用 construct signature 之类的 { new(): IAuthProvider }new () => IAuthProvider:

type AuthProviderNamespace = {
  [K in typeof providerNames[number]]: new () => IAuthProvider
}

然后一切正常:

const providers: AuthProviderNamespace = { Email, Password }

Playground link to code