从 Object.assign 返回和从 Typescript 中的自定义对象返回有什么不同

What's different between returning from Object.assign and from customized object in Typescript

我在 NestJS 中使用 typeorm,在 app.module.ts 我尝试通过申请 forRootAsync

来初始化我的数据库设置
TypeOrmModule.forRootAsync({
    imports: [ConfigModule],
    inject: [ConfigService],
    useFactory: async (configService: ConfigService) => ({
        type: configService.get('database.type'),
        host: configService.get('database.host'),
        port: configService.get('database.port'),
        username: configService.get('database.username'),
        password: configService.get('database.password'),
        database: configService.get('database.database'),
        entities: configService.get('database.entities'),
        synchronize: configService.get('database.synchronize'),
        logging: configService.get('database.logging'),
    }),
}),

在编译过程中出现以下错误:

error TS2322: Type '(configService: ConfigService) => Promise<{ type: "mysql" | "mariadb" | "postgres" | "cockroachdb" | "sqlite" | "mssql" | "sap" | "oracle" | "cordova" | "nativescript" | "react-native" | "sqljs" | "mongodb" | "aurora-data-api" | "aurora-data-api-pg" | "expo" | "better-sqlite3"; ... 7 more ...; logging: LoggerOptions...' is not assignable to type '(...args: any[]) => TypeOrmModuleOptions | Promise<TypeOrmModuleOptions>'.
  Type 'Promise<{ type: "mysql" | "mariadb" | "postgres" | "cockroachdb" | "sqlite" | "mssql" | "sap" | "oracle" | "cordova" | "nativescript" | "react-native" | "sqljs" | "mongodb" | "aurora-data-api" | "aurora-data-api-pg" | "expo" | "better-sqlite3"; ... 7 more ...; logging: LoggerOptions; }>' is not assignable to type 'TypeOrmModuleOptions | Promise<TypeOrmModuleOptions>'.
    Type 'Promise<{ type: "mysql" | "mariadb" | "postgres" | "cockroachdb" | "sqlite" | "mssql" | "sap" | "oracle" | "cordova" | "nativescript" | "react-native" | "sqljs" | "mongodb" | "aurora-data-api" | "aurora-data-api-pg" | "expo" | "better-sqlite3"; ... 7 more ...; logging: LoggerOptions; }>' is not assignable to type 'Promise<TypeOrmModuleOptions>'.
      Type '{ type: "mysql" | "mariadb" | "postgres" | "cockroachdb" | "sqlite" | "mssql" | "sap" | "oracle" | "cordova" | "nativescript" | "react-native" | "sqljs" | "mongodb" | "aurora-data-api" | "aurora-data-api-pg" | "expo" | "better-sqlite3"; ... 7 more ...; logging: LoggerOptions; }' is not assignable to type 'TypeOrmModuleOptions'.
        Type '{ type: "mysql" | "mariadb" | "postgres" | "cockroachdb" | "sqlite" | "mssql" | "sap" | "oracle" | "cordova" | "nativescript" | "react-native" | "sqljs" | "mongodb" | "aurora-data-api" | "aurora-data-api-pg" | "expo" | "better-sqlite3"; ... 7 more ...; logging: LoggerOptions; }' is not assignable to type '{ retryAttempts?: number; retryDelay?: number; toRetry?: (err: any) => boolean; autoLoadEntities?: boolean; keepConnectionAlive?: boolean; verboseRetryLog?: boolean; } & Partial<AuroraDataApiConnectionOptions>'.
          Type '{ type: "mysql" | "mariadb" | "postgres" | "cockroachdb" | "sqlite" | "mssql" | "sap" | "oracle" | "cordova" | "nativescript" | "react-native" | "sqljs" | "mongodb" | "aurora-data-api" | "aurora-data-api-pg" | "expo" | "better-sqlite3"; ... 7 more ...; logging: LoggerOptions; }' is not assignable to type 'Partial<AuroraDataApiConnectionOptions>'.
            Types of property 'type' are incompatible.
              Type '"mysql" | "mariadb" | "postgres" | "cockroachdb" | "sqlite" | "mssql" | "sap" | "oracle" | "cordova" | "nativescript" | "react-native" | "sqljs" | "mongodb" | "aurora-data-api" | "aurora-data-api-pg" | "expo" | "better-sqlite3"' is not assignable to type '"aurora-data-api"'.
                Type '"mysql"' is not assignable to type '"aurora-data-api"'.

19             useFactory: async (configService: ConfigService) => ({
               ~~~~~~~~~~

  node_modules/@nestjs/typeorm/dist/interfaces/typeorm-options.interface.d.ts:19:5
    19     useFactory?: (...args: any[]) => Promise<TypeOrmModuleOptions> | TypeOrmModuleOptions;
           ~~~~~~~~~~
    The expected type comes from property 'useFactory' which is declared here on type 'TypeOrmModuleAsyncOptions'

但是如果我在返回之前应用 Object.assign() 它将通过

TypeOrmModule.forRootAsync({
    imports: [ConfigModule],
    inject: [ConfigService],
    useFactory: async (configService: ConfigService) =>
        Object.assign({
            type: configService.get('database.type'),
            host: configService.get('database.host'),
            port: configService.get('database.port'),
            username: configService.get('database.username'),
            password: configService.get('database.password'),
            database: configService.get('database.database'),
            entities: configService.get('database.entities'),
            synchronize: configService.get('database.synchronize'),
            logging: configService.get('database.logging'),
        }),
}),

这是因为 Object.assign() 将对象转换为 any 类型吗? 异步初始化 typeorm 的常用方法是什么?

正如我从您的日志中看到的那样 - Type '"mysql"' is not assignable to type '"aurora-data-api"'.

您可以参考- Overriding options defined in ormconfig。 Here它明确提到了附加自定义命名策略或自定义记录器的示例。

TypeORM 提供了 getConnectionOptions 函数,可以从 ormconfig 文件或环境变量中读取连接选项。 - Hint mentioned on TypeORM Integration

搜索后我找到了这个帖子。

https://github.com/nestjs/nest/issues/1119

它说我们需要具体分配类型。

所以我更改了 return 对象中的类型 属性:

type: configService.get('database.type') as 'mysql',

但是如果我删除 Object.assign(),我仍然会遇到同样的编译错误,我注意到行

password: configService.get('database.password')

将 configService.get() 转换为

的值
string | (() => string) | (() => Promise<string>);

这导致了问题,所以我需要传递类型,最终配置如下所示:

TypeOrmModule.forRootAsync({
    imports: [ConfigModule],
    inject: [ConfigService],
    useFactory: async (configService: ConfigService) => ({
        type: configService.get('database.type') as 'mysql',
        host: configService.get('database.host'),
        port: configService.get('database.port'),
        username: configService.get('database.username'),
        password: configService.get('database.password'),
        database: configService.get<string>('database.database'),
        entities: [configService.get('database.entities')],
        synchronize: configService.get<boolean>('database.synchronize'),
        logging: configService.get<boolean>('database.logging'),
    }),
})

但我仍然不知道为什么它会将密码强制转换为那种奇怪的类型。