unjs / defu

🌊 Assign default properties recursively
MIT License
1.06k stars 22 forks source link

two subset defaults. #41

Closed shtse8 closed 2 years ago

shtse8 commented 2 years ago

interface UploadOptions<T extends StorageList> {
  storeKey?: keyof T
  id?: string
}

interface UrlUploadOptions {
  lazy?: boolean
}

async uploadByUrl(url: string, options?: UploadOptions<typeof this.storages> & UrlUploadOptions): Promise<Image> {
  const opts = defu(options ?? {}, this.defaultUploadOptions, this.defaultUrlUploadOptions)
 // ...
}

Type Error:

TS2559: Type 'UrlUploadOptions' has no properties in common with type 'UploadOptions '.

It's because of the type

<Source extends Input, Defaults extends Input>(source: Source, ...defaults: Defaults[]): MergeObjects<Source, Defaults>;

Could we change it to Partial<Defaults>?

Currently I can merge two defaults into one to apply.

const opts = defu(options ?? {}, { ...this.defaultUploadOptions, ...this.defaultUrlUploadOptions })

but, it needs merging before applying. or call defu twice... sounds stupid.

pi0 commented 2 years ago

/cc @danielroe

danielroe commented 2 years ago

defu already accepts partials of the desired type. I think the issue in your case is due to the untyped {} you are passing as the first argument, and I think you can resolve in your own project with:

+   // for readability
+   type Options = UploadOptions<typeof this.storages> & UrlUploadOptions

-   const opts = defu(options ?? {}, this.defaultUploadOptions, this.defaultUrlUploadOptions)
+   const opts = defu(options ?? {} as Partial<Options>, this.defaultUploadOptions, this.defaultUrlUploadOptions)

Let me know if I've misunderstood what you are asking for.