在TypeScript中,如何使在构造函数中传递的接口的属性在方法的参数的接口中是可选的?

brc7rcf0  于 2023-05-01  发布在  TypeScript
关注(0)|答案(1)|浏览(141)

我有一个Logger类,它可以在构造函数中接收默认的可选值:

interface Log {
  level: string
  scope: string
  source: string
  message: string
}

type LogDefaults = Partial<Log>
type LogInput = Log

class Logger {
  constructor(private defaults: LogDefaults = {}) {}

  public log(log: LogInput): void {
    console.log({ ...this.defaults, ...log })
  }
}

我希望用户在构造函数中作为“默认值”传递的属性在log方法中是可选的。
有没有一种方法可以定义“LogInput”类型,以便在运行时只需要“LogDefaults”中没有提供的属性?
这应该可以工作:

const logger = new Logger()
logger.log({
  scope: 'my-scope',
  source: 'my-souce',
  level: 'info',
  message: 'my message'
})

这也应该起作用:

const logger = new Logger({ scope: 'my-scope', source: 'my-souce' })
logger.log({ 
    level: 'info',
    message: 'my message'
})

这不应该工作(缺少必需的“source”属性):

const logger = new Logger({ scope: 'my-scope' })
logger.log({ 
    level: 'info',
    message: 'my message'
})
m3eecexj

m3eecexj1#

可以使用generics解决。Playground链接

interface Log {
  level: string
  scope: string
  source: string
  message: string
}

class Logger<T extends Partial<Log>> {
  constructor(private defaults?: T) {}

  public log(log: Omit<Log, keyof T> & Partial<Log>) {
    console.log({ ...this.defaults, ...log })
  }
}

const logger1 = new Logger()
logger1.log({
  scope: 'my-scope',
  source: 'my-souce',
  level: 'info',
  message: 'my message'
})

const logger2 = new Logger({ scope: 'my-scope', source: 'my-souce' })
logger2.log({ 
    level: 'info',
    message: 'my message'
})

const logger3 = new Logger({ scope: 'my-scope' })

// @ts-expect-error source is missing
logger3.log({ 
    level: 'info',
    message: 'my message'
})

// still allows to override
logger3.log({
  scope: 'my-scope',
  source: 'my-souce',
  level: 'info',
  message: 'my message'
})

编辑:根据@Axnyff的建议更新

相关问题