The commonName
and animal
的属性Pet
自然地使Pet
a 受歧视联盟 https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions哪里的commonName
属性是判别式。您的实施makeSound()
会毫无问题地输入检查,如果Pet
是一个如此受歧视的工会。
唯一的问题是Pet
is a class https://www.typescriptlang.org/docs/handbook/2/classes.html,并且类实例类型需要定义为an interface https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#interfaces,并且接口不能是union https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types根本没有,更不用说是一个受歧视的工会了。
相反,你试图代表Pet
as generic https://www.typescriptlang.org/docs/handbook/2/generics.html。这捕获了约束commonName
and animal
或多或少(好吧,C
本身可以是联合类型,这会破坏事物,但是对于this我们会忽略潜在的不健全情况。出于我们的目的,我们可以假设C
将是"cat"
or "dog"
或任何其他单一成员keyof TypeMap
)。但编译器不允许makeSound()
键入检查。
所以我们必须重构(或者用类型断言 https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions抑制错误,但我们不要这样做)。
一种潜在的重构是抽象签入makeSound()
进行查找,这样我们就不会进行具体情况的控制流程。它看起来像这样:
const petSound = {
cat: (cat: Cat) => cat.purr(),
dog: (dog: Dog) => dog.bark()
}
class Pet<C extends keyof TypeMap> {
makeSound() {
petSound[this.commonName](this.animal); // error
}
}
问题是编译器无法遵循类型之间的相关性petSound[this.commonName]
and this.animal
。这就是我一直称之为“相关联合”的问题,如中所述微软/TypeScript#30581 https://github.com/microsoft/TypeScript/issues/30581。此问题的修复已于微软/TypeScript#47109 https://github.com/microsoft/TypeScript/pull/47109并涉及给予petSound
a 分布对象类型编译器可以跟踪相关性。它看起来像这样:
const petSound: { [C in keyof TypeMap]: (animal: TypeMap[C]) => void } =
{
cat: cat => cat.purr(),
dog: dog => dog.bark()
};
仅仅通过给予petSound
a 映射类型 https://www.typescriptlang.org/docs/handbook/2/mapped-types.html迭代keyof TypeMap
, 以上makeSound()
编译没有错误:
class Pet<C extends keyof TypeMap> {
makeSound() {
petSound[this.commonName](this.animal); // okay
}
}
看起来不错!
(请注意,这仍然不合理;有人可以指定C
as keyof TypeMap
然后给出一个完全错误的animal
对于给定的属性commonName
财产。但是 TypeScript 故意忽略了这种不合理性,以便使这个相关联合的事情发挥作用。看微软/TypeScript#48730 https://github.com/microsoft/TypeScript/issues/48730了解更多信息)。
Playground 代码链接 https://www.typescriptlang.org/play?#code/MYGwhgzhAEDCYBdoG9oAcCuAnLAKAlCgPQBUAdBSUdAL60BQokMAIgPYDmK0ARmFgGsCxcpWp0a9AJYA7BAFMsAMzDB50ACoBPNPICyYNCnoBIYIgBccRAG5TAE05X2HO5MZsZEJLoQBlNgwZeytUAG1YaFloAXktNiVNHX1DAF0rXDAZKQBbMBArbV0DNAjUwgBeAD5oADc2KXtaaAr6ZFNzBCtOlprOskwcAgAaBydoRy5qic4yPkECeho7RnAoaAAFeQQAHkj5AA8FYJhY+MSilLQa9rM2HJzPADkwHPkrWDsTLNz8wuSSmUvsBPN4sBhgAg2HgQQ9nq93nBhtAfnkCklioYyoRbiYEAALKQQMiwx4yF5vFrQUnwt5fPGE4mo-JU5kgL6SEx5WIBIL2YS43y84JhAlEkn3MkU+SpXBipnZNH4GzQIjUNgCMBaUySSRAA