繁体   English   中英

如何定义具有键类型和值类型之间相关性的映射,而它们都是联合

How to define Map with correlation between a key type and a value type, while they both are unions

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

这是显示我想要实现的目标的示例。 除了两个问题外,它几乎可以工作:

  1. 设置不显示错误代码的错误
  2. Immer Draft 类型(或任何 DeepWritable 实用程序类型)完全搞砸了这个技巧

基本上在我看来,我在这里所做的并不是真正的一件事。 所以问题是:有没有其他方法可以做同样的事情?

type Opaque<Type, Token = unknown> = Type & {
  readonly __opaque__: Token
}

type AnimalId = CatId | DogId

type Animal = Cat | Dog

type CatId = Opaque<number, Cat>

type Cat = {
  readonly kind: 'Cat'
  readonly id: CatId
}

type DogId = Opaque<number, Dog>

type Dog = {
  readonly kind: 'Dog'
  readonly id: DogId
}

const cat: Cat = {
    kind: 'Cat',
    id: 1 as CatId,
}

const dog: Dog = {
    kind: 'Dog',
    id: -1 as DogId,
}

const animals: Map<CatId, Cat> & Map<DogId, Dog> & Map<AnimalId, Animal> = new Map()

animals.set(cat.id, cat) // no error should be here

animals.set(cat.id, dog) // wanna see error here

const test1: Cat | undefined = animals.get(cat.id) // no error should be here

const test2: Dog | undefined = animals.get(dog.id) // no error should be here

const test4: Animal | undefined = animals.get(1 as AnimalId) // no error should be here

const test3 = animals.get(3) // wanna see error here
1 个回复

交集Map<CatId, Cat> & Map<DogId, Dog>概念上应该足以为您提供所需的行为,但实际上这不起作用。 函数类型的交集会产生重载,而 TypeScript 中的重载调用签名是单独解析的。 它们不组合以允许单个调用调用两个调用签名(请参阅microsoft/TypeScript#14107 )。 因此,仅使用Map<CatId, Cat> & Map<DogId, Dog> ,您无法调用animals.get(1 as AnimalId) AnimalId既不是CatId也不是DogId ,这是两个单独调用签名中的每一个所要求的。


为了解决这个问题,您显然已经添加了“缺失的” Map<AnimalId, Animal> 不幸的是,这太过分了。 您不仅会得到理想的get()行为,还会得到不理想的set()行为。 因为cat.id是一个AnimalId ,而dog是一个Animal ,所以Map<AnimalId, Animal>肯定会允许你调用animals.set(cat.id, dog) 我不会深入探讨协变和逆变的迂腐细节,但一般来说,如果阅读接受事物的联合,那么写作应该接受事物的交集,而不是联合。 所以唯一的方法, Map<AnimalId, Animal>支持是涉及阅读的内容的。

对我们来说幸运的是,TypeScript 标准库中定义了一个ReadonlyMap接口,它正好用于此目的。 所以我倾向于像这样注释animals

const animals: Map<CatId, Cat> & Map<DogId, Dog>
  & ReadonlyMap<AnimalId, Animal> = new Map();

一旦你这样做了,你就会得到你正在寻找的行为,至少对于你的示例代码:

animals.set(cat.id, cat) // okay
animals.set(cat.id, dog) // error, no overload matches this call
const test1: Cat | undefined = animals.get(cat.id) // okay
const test2: Dog | undefined = animals.get(dog.id) // okay
const test4: Animal | undefined = animals.get(1 as AnimalId) // okay
const test3 = animals.get(3) // error, number is not AnimalId

当然,可能存在此定义不支持的其他用例。 重载确实有一些奇怪的怪癖。 如果您真的很在意,您可能需要手写自己的界面,该界面的行为与您期望的多类型Map行为完全相同。 这是我之前针对不同案例做过的有趣练习(请参阅此问题),老实说,它并没有那么糟糕。 但我不会在这里深入讨论,尤其是如果上述更简单的交集适用于您的用例。

Playground 链接到代码

1 如何在Scala中定义具有特定类型键和任何单一类型值的映射?

我需要的是像 但所有值必须是任何一种特定类型 。 例如,不是一个值是Int,另一个值是Double,第三个值是String-所有记录都应具有相同的特定类型,并向下转换为Any。 我将把地图作为半类型不可知函数的参数,使用匹配/大小写确定类型并执行特定算法。 该函数实际上将支持某 ...

2 如何匹配地图返回类型的键和值?

我正在研究一种方法,其中getOrdersForCustomer方法的返回类型为Map&lt;Integer, List&lt;Order&gt;&gt;并且每个customerId(地图的Integer)在遍历订单列表时都需要使用其各自的订单。 订单已与客户ID相关联。 我得出以下结论: ...

3 如何获取地图的键和值类型

我有此代码,应用程序需要检查一下给定的Map的键是否为String : 我可以通过使用迭代器获取第一项并通过instanceof检查来实现,但这会导致我使用两个迭代器。 获取Map键类型的最佳方法是什么? 更新:我创建一个MapHelper类: 这样够好吗? ...

2015-01-03 15:03:34 3 3300   java
5 Scala中Map键和值类型参数之间的依赖关系[重复]

这个问题在这里已有答案: 关联参数化类型 4个答案 有时,对映射中的键类型和值之间的依赖关系进行编码可能很有用。 请考虑以下类型: 这里序列中的每一对应该具有相同的类型T 但就类似地图的使用而言,这种类型并不是很方便。 但是我无法表达Map[K, V] ...

7 如何定义允许对象键或值的类型

我有一堆按对象分组的常量,但我无法正确输入。 我希望能够使用字符串或通过访问对象来传递对象属性。 我想要什么: 我到目前为止的尝试: 有没有办法为对象的键或值定义类型? 如果是这样,如何? ...

9 重载<<以输出地图的key_type和Mapd_type

我有一个课程目录的类,该课程目录的类型为map&lt;string, string&gt; Courses 。 我想重载&lt;&lt;作为朋友运算符,以便当我输出例如Courses["TMA4100"] ,它将输出"TMA4100"和课程名称,而不仅是名称。 原因是我可以将目录存储在文件中 ...

10 值类型依赖于键类型的 Map 类型?

我想知道是否有可能实现像contrib的Data.SortedMap类的东西,例如,键类型可以是Key n ,值类型可以是Value n ,其中n是相同的Nat ? 对于Map (Key n) (Value n) (失败并显示“No such variable n”),一些通常的函数会有这样的类型 ...

2020-01-12 17:58:16 1 68   idris
暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM