对于一个小型的教育侧项目我在工厂类中使用Phaser CE框架,这样根据我用预定义样式编写的JSON文件,由它生成的 Phaser.Text
元素会自动设置样式 .
但是,我还有一个 INamed
属性,我坚持使用有名字的东西 . 这也在 Array<>
上有扩展,让我可以轻松地通过名称从数组中获取项目 .
因此,理论上我可以采取这样的数据:
styles.json:
{
"text": [
{
"name": "default",
"fill": "#FFF",
"stroke": "#333",
"strokeWidth": 1
},
{
"name": "snazzy",
"fill": "#F33",
"stroke": "#633",
"strokeWidth": 2
},
]
}
......并使用我们的文本工厂......
TextFactory.ts:
namespace Main.UI {
export class TextFactory {
public styles: (Phaser.PhaserTextStyle & INamed)[] = [];
public constructor() {}
public initialize() {
const data = game.cache.getJSON('ui-styles');
const textStyles = data['text'];
for (let current of textStyles) {
this.styles.push(current);
}
}
public create(
x: number,
y: number,
text: string,
style?: string
): Phaser.Text {
let styleData: (Phaser.PhaserTextStyle & INamed);
if (!style)
styleData = this.styles[0];
else
styleData = this.styles.getByName(style);
// !!! Problem is here !!!
const newText = game.add.text(x, y, text, <Phaser.PhaserTextStyle>styleData);
return newText;
}
}
}
...并在游戏状态下使用它:
GameState.ts:
namespace Main.States {
export class GameState extends Phaser.State {
private textFactory: UI.TextFactory = null;
public preload(): void {
game.load.json('ui-styles', 'assets/data/styles.json');
}
public create(): void {
this.textFactory = new UI.TextFactory();
this.textFactory.initialize();
const testText = this.textFactory.create(2, 2, "This should be white with a dark gray outline...");
const otherText = this.textFactory.create(2, 52, "SNAZZY!", "snazzy");
}
}
}
如果您使用Phaser中的相关样板运行该常规设置,则文本将呈现,但将为黑色且未设置样式 . 我已经执行了一些健全性检查,发现联合类型 (Phaser.PhaserTextStyle & INamed)
似乎是在给我带来麻烦 - 对 game.add.text
的调用只是期待 Phaser.PhaserTextStyle
.
我尝试将 TextFactory.create
中的 textStyle
变量转换为 Phaser.PhaserTextStyle
,但这并没有保存并构建我的更改,并添加了调试消息,但那些没有明确完成 . 因此,我的问题......
Question: 以什么方式可以在TypeScript中使用 (A & B)
类型的对象,并将其用作 A
或 B
类型?
2 回答
我不认为对象的类型与问题有任何关系 .
game.add.text
函数可能对对象的额外name
属性有问题 .类型断言在运行时不执行任何操作,因此您可以使用它们来删除属性,您可以仅使用它们来更改编译器知道的类型(在这种情况下无效) .
您可以使用delete删除额外属性:
或者你可以创建一个没有属性的新对象,并使用它来使用它:
简答:你不能 .
答案很长:将
A & B
用作A
或B
的唯一类型安全方法是使用类型保护 . 然而,即使这种方法也有局限性 .考虑以下边缘情况,其中两个形状都具有相同名称的字段(
id
):相交
A
和B
告诉TypeScriptid
属性必须同时为string & number
,这是无法完成的 . 尽管在类型级别上存在这样的概念,但它不能具有运行时表示 .即使 - 假设 - 我们可以有
Intersection
(有人可以使用类型断言),TypeScript将允许我们编写将在运行时爆炸的代码 .可以通过创建用户定义的类型保护来降低风险 .
不幸的是,这些需要存在于运行时,没有什么能阻止开发人员错误地实现它们 .