提问人:Rostys 提问时间:9/1/2023 最后编辑:Rostys 更新时间:9/1/2023 访问量:44
TypeScript:对 typeguard 使用类型转换
TypeScript: Using typecasting for typeguard
问:
我有带有构造函数的类,可以接受两种类型的对象,然后根据它得到的对象类型,执行不同的操作。
我已经看到可以使用关键字。
但我觉得不对劲。as
export type Angle = {
cos: number;
sin: number
}
export type VectorAngleInit = {
angle: Angle,
magnitude: number
}
export type VectorDInit = {
dx: number,
dy: number
}
export class Vector {
#dx: number;
#dy: number;
constructor(init: VectorAngleInit | VectorDInit) {
if ((init as VectorAngleInit)?.angle) {
const angleInit = init as VectorAngleInit
this.#dx = angleInit.magnitude * angleInit.angle.cos;
this.#dy = angleInit.magnitude * angleInit.angle.sin;
} else {
const dInit = init as VectorDInit
this.#dx = dInit.dx
this.#dy = dInit.dy
}
}
}
我应该以另一种方式做吗?如果是这样,你认为哪种方式更好?
答:
2赞
jcalz
9/1/2023
#1
您可以使用 in 运算符缩小来检查是否存在 in 并将范围缩小到所需的联合成员,而无需类型断言(您称之为“强制转换”):
"angle"
init
init
export class Vector {
#dx: number;
#dy: number;
constructor(init: VectorAngleInit | VectorDInit) {
if ("angle" in init) {
this.#dx = init.magnitude * init.angle.cos;
this.#dy = init.magnitude * init.angle.sin;
} else {
this.#dx = init.dx
this.#dy = init.dy
}
}
}
2赞
ColaFanta
9/1/2023
#2
您需要的东西称为类型谓词,这是缩小联合类型范围的官方方法。它是一个具有特殊返回类型的函数,该返回类型实际上是一个布尔值,但通知编译器您实际需要做的是谓词该类型,而不仅仅是返回布尔值。x is SomeType
typescript
与您的问题相关的示例可能是这样的:
首先定义函数type predicate
export type VectorAngleInit = {
angle: Angle
magnitude: number
}
// type predicate predicating whether u is of type VectorAngleInit
export function isVectorAngleInit(u: unknown): u is VectorAngleInit {
return !!u && typeof u === 'object' && (u as VectorAngleInit).angle instanceof Angle
}
export type VectorDInit = {
dx: number
dy: number
}
// type predicate predicating whether u is of type VectorDInit
export function isVectorDInit(u: unknown): u is VectorDInit {
return !!u && typeof u === 'object' && typeof (u as VectorDInit).dx === 'number'
}
然后在构造函数中使用它:
export class Vector {
#dx: number
#dy: number
constructor(init: VectorAngleInit | VectorDInit) {
if (isVectorAngleInit(init)) {
// notice that type of `init` is auto inferred within if block
this.#dx = init.magnitude * init.angle.cos
this.#dy = init.magnitude * init.angle.sin
}
if(isVectorDInit(init)){
this.#dx = init.dx
this.#dy = init.dy
}
}
}
评论