使用计算属性时如何设置类型?
How to set type when computed property is used?
我有两个接口。
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:元素隐式具有 'any' 类型,因为“质量”类型的表达式 | "weight"' 不能用于索引类型 'Person | Dog'.
API 可以 return 狗或人,这取决于其他参数。我想知道告诉 TS 如果玩家是人使用 'weight' 并且如果玩家是狗使用 'mass' 的最佳方式是什么。我不想使用“任何”类型。
TypeScript 实际上在这里很有用:例如,如果 attribute
是 "mass"
,但 player
是 Person
,那么它将是一个合理的错误,因为mass
属性 在 Person
个实例上不存在。
你要避免这个错误,你需要改变方法。您可以添加 player
中实际存在的 attribute
的运行时检查,但我认为您应该使用 isDog
变量(它更符合逻辑):
const isDog = "mass" in player;
const mass = isDog ? player.mass : player.weight;
if (mass === 0) return;
用户@jonsharpe 在 中提出了一个有价值的模式:将相似的功能集中在一个 属性 上,即,如果 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`
这应该足以解决您的问题(尽管我建议也为 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, also see an example.
我有两个接口。
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:元素隐式具有 'any' 类型,因为“质量”类型的表达式 | "weight"' 不能用于索引类型 'Person | Dog'.
API 可以 return 狗或人,这取决于其他参数。我想知道告诉 TS 如果玩家是人使用 'weight' 并且如果玩家是狗使用 'mass' 的最佳方式是什么。我不想使用“任何”类型。
TypeScript 实际上在这里很有用:例如,如果 attribute
是 "mass"
,但 player
是 Person
,那么它将是一个合理的错误,因为mass
属性 在 Person
个实例上不存在。
你要避免这个错误,你需要改变方法。您可以添加 player
中实际存在的 attribute
的运行时检查,但我认为您应该使用 isDog
变量(它更符合逻辑):
const isDog = "mass" in player;
const mass = isDog ? player.mass : player.weight;
if (mass === 0) return;
用户@jonsharpe 在 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`
这应该足以解决您的问题(尽管我建议也为 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, also see an example.