使用计算属性时如何设置类型?

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",但playerPerson,那么这将是一个合法错误,因为Person.mass 不存在 您不必从外部做出这种区分。 PersonDog 都应该以同样的方式暴露它们的质量(extends Massive?),所以这不会传播到你的整个代码库。 【参考方案1】:

用户@jonsharpe 在their comment 中建议了一个有价值的模式:将相似的功能集中在一个属性上,即如果weightmass 传达相同的想法,它们应该被称为相同的(注意PersonDog 具有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",但 playerPerson,那么这将是一个合理的错误,因为 mass 属性在 @ 上不存在987654327@ 个实例。

你避免了这个错误,你需要改变方法。您可以添加对player 中实际存在的attribute 的运行时检查,但我认为您应该使用isDog 变量(这更合乎逻辑):

const isDog = "mass" in player;
const mass = isDog ? player.mass : player.weight;

if (mass === 0) return;

Try it.

【讨论】:

以上是关于使用计算属性时如何设置类型?的主要内容,如果未能解决你的问题,请参考以下文章

gis属性表没有area如何计算面积

计算属性“解析错误:'' 预计在”

使用类型中的“in”键入具有计算属性的类型

当计算使用后台线程时,如何正确声明计算属性?

...mapState() 中定义的计算属性没有设置器

TypeScript 条件类型和计算对象属性名称