使用计算属性时如何设置类型?
Posted
技术标签:
【中文标题】使用计算属性时如何设置类型?【英文标题】:How to set type when computed property is used? 【发布时间】:2021-12-17 01:56:34 【问题描述】:我有两个接口。
interface Person
name: string;
weight: number;
interface Dog
name: string;
mass: number
const attribute = isDog ? 'mass' : 'weight';
const player: Person | Dog = "Object with specific type"
if (player[attribute] === 0) return;
我有这个错误:TS7053:元素隐式具有“任何”类型,因为表达式类型为“质量”| "weight"' 不能用于索引类型 'Person |狗'。
API 可以返回 Dog 或 Person,这取决于其他参数。我想知道告诉 TS 如果玩家是人使用“重量”,如果玩家是狗使用“质量”的最佳方式是什么。我不想使用“任何”类型。
【问题讨论】:
好吧,TypeScript 试图在这里提供帮助。如果attribute
是"mass"
,但player
是Person
,那么这将是一个合法错误,因为Person.mass
不存在
您不必从外部做出这种区分。 Person
和 Dog
都应该以同样的方式暴露它们的质量(extends Massive
?),所以这不会传播到你的整个代码库。
【参考方案1】:
用户@jonsharpe 在their comment 中建议了一个有价值的模式:将相似的功能集中在一个属性上,即如果weight
和mass
传达相同的想法,它们应该被称为相同的(注意Person
和Dog
具有name
属性,它传达了相同的想法)。通常这是通过实现通用接口的对象(例如本例中的Massive
)来完成的。
你可以这样做:
interface Massive
mass: number;
interface Person extends Massive
name: string;
// other Person-specific properties, no need to repeat `mass`
interface Dog extends Massive
name: string;
// other Dog-specific properties, no need to repeat `mass`
function doSomethingIfHasMass(value: Massive)
if (value.mass === 0) return;
// otherwise do the thing
const player: Person | Dog;
doSomethingIfHasMass(player);
// shouldn't cause compile errors,
// because `Person | Dog` is assignable to `Massive`,
// since each `Person` and `Dog` individually is `Massive`
Try it.
这应该足以解决您的问题(尽管我建议也为name: string
属性创建一个Named
接口)。但是,还有另一个功能,您会发现它很有用。 hasMass
回答问题“物体有质量吗?”(如果它的质量大于零,它会回答问题),isMassive
会回答问题“物体是否符合到Massive
接口?”(如果它具有“质量”属性,它会这样做):
function isMassive(value: object): value is Massive
return "mass" in value;
现在你可以在你的函数中提供各种对象,如果对象的形状不正确,它会默默地失败而不会出错(这种行为是否对你有好处是你的决定):
function doSomethingIfMassiveAndHasMass(value: object)
if (!isMassive(value)) return;
if (value.mass === 0) return;
// otherwise do the thing
declare const something: object;
doSomethingIfMassiveAndHasMass(something);
// shouldn't cause compile errors,
// because while any object could be passed in this function,
// only `Massive` objects with non-zero mass will actually trigger its logic
Try it,还有see an example。
【讨论】:
【参考方案2】:TypeScript 在这里实际上很有帮助:例如,如果 attribute
是 "mass"
,但 player
是 Person
,那么这将是一个合理的错误,因为 mass
属性在 @ 上不存在987654327@ 个实例。
你避免了这个错误,你需要改变方法。您可以添加对player
中实际存在的attribute
的运行时检查,但我认为您应该使用isDog
变量(这更合乎逻辑):
const isDog = "mass" in player;
const mass = isDog ? player.mass : player.weight;
if (mass === 0) return;
Try it.
【讨论】:
以上是关于使用计算属性时如何设置类型?的主要内容,如果未能解决你的问题,请参考以下文章