dmonad / lib0

Monorepo of isomorphic utility functions
MIT License
345 stars 63 forks source link

map.setIfUndefined doesn't consider inheritance in parameters #82

Closed byrond closed 9 months ago

byrond commented 9 months ago

Describe the bug When we attempt to call map.setIfUndefined(A, 'key', () => new B) where class B extends the class used in Map A, we get the following:

Argument of type 'Map<string, A>' is not assignable to parameter of type 'Map<string, B>'.
  Type 'A' is missing the following properties from type 'B': ... ts(2345)

This seems to be related to its definition:

 * @function
 * @template V,K
 * @template {Map<K,V>} MAP
 * @param {MAP} map
 * @param {K} key
 * @param {function():V} createT
 * @return {V}

We have worked around the issue by copying the logic inline instead of using map.setifUndefined, but it would be great to be able to use it with inherited classes.

To Reproduce Steps to reproduce the behavior:

Use the following JS, and attempt to generate types with tsc:

import * as map from 'lib0/map'

class A {
  constructor() {
    this.property1 = 1
  }
}

class B extends A {
  constructor() {
    super()
    this.property2 = 2
  }
}

/**
 * @type {Map<string, A>}
 */
const set = new Map()

const item = map.setIfUndefined(set, 'key', () => new B)

Expected behavior We can call map.setIfUndefined(A, 'key', () => new B) where class B extends the class used in Map A, and the function adds a new instance of B to the map without errors.

Screenshots If applicable, add screenshots to help explain your problem. Tip: you can drag-drop images into this textarea.

Environment Information

Additional context Add any other context about the problem here.

dmonad commented 9 months ago

Makes sense. I fixed it.