typescript - 如何将联合类型解释为组件类型之一
问题描述
对于我正在做的一个小教育项目,我在工厂类中使用 Phaser CE 框架,这样Phaser.Text
由它生成的元素会根据我使用预定义的 JSON 文件自动设置样式样式。
但是,我也有一个INamed
属性,我坚持使用有名字的东西。这也有扩展Array<>
,让我可以轻松地按名称从数组中获取项目。
因此,理论上我可以获取这样的数据:
样式.json:
{
"text": [
{
"name": "default",
"fill": "#FFF",
"stroke": "#333",
"strokeWidth": 1
},
{
"name": "snazzy",
"fill": "#F33",
"stroke": "#633",
"strokeWidth": 2
},
]
}
...并使用我们的文本工厂...
文本工厂.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;
}
}
}
...并在游戏状态下使用它:
游戏状态.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
.
我尝试将textStyle
变量TextFactory.create
转换为 a Phaser.PhaserTextStyle
,但这似乎并不有效 - 我的文本仍然呈现无样式。我做了一些进一步的“愚蠢的开发者”检查,比如确保我已经保存并构建了我的更改,并添加了调试消息,但这些并没有产生任何见解来帮助了解我清楚地做了什么新的愚蠢的事情。因此,我的问题...
问题:我可以通过什么方式获取(A & B)
TypeScript 中类型的对象并将其用作A
orB
类型?
解决方案
简短的回答:你不能。
长答案:唯一使用类型安全的方法是A & B
使用类型保护。然而,即使这种方法也有局限性。A
B
考虑以下边缘情况,其中两个形状都具有相同名称 ( id
) 的字段:
interface A {
name: string;
id: string;
}
interface B {
id: number;
}
type Intersection = A & B;
const test: Intersection = {
id: 0, // Error — cannot be implemented! Nothing is both a string and a number
name: ''
}
相交A
并B
告诉 TypeScriptid
属性需要同时是两者string & number
,这是无法实现的。即使这样的概念存在于类型级别,它也不能有运行时表示。
即使——假设——我们可以有一个Intersection
(有人可以使用类型断言),TypeScript 将允许我们编写会在运行时爆炸的代码。
declare function alpha(argument: A): void;
declare function beta(argument: B): void;
declare const intersection: Intersection;
alpha(intersection); // TypeScript allows that, but it can fail in runtime if `alpha` expects `id` to be of type `string`.
可以通过创建用户定义的类型保护来降低风险。
/**
* Type-safe approach.
*/
declare function isA(argument: unknown): argument is A;
declare function isB(argument: unknown): argument is B;
if (isA(intersection)) {
alpha(intersection);
}
if (isB(intersection)) {
beta(intersection);
}
不幸的是,这些需要存在于运行时,并且没有什么可以阻止开发人员错误地实现它们。
推荐阅读
- docker - vue-cli-service build :模块构建失败(来自 ./node_modules/html-webpack-plugin/lib/loader.js)
- c++ - 用单个字符填充字符串流
- ruby-on-rails - 无法以 html 格式呈现响应
- css - Css,Safari:悬停和子可见性
- c# - 如何以多对多关系保存 EF Core 3.1.3 中的更改?
- python - 类中的析构函数在使用类时不断调用它自己
- c - libgit2 不返回有效的 blob
- android - 继续收听所有活动的广播接收器
- tensorflow - 模型的损失增加仅适用于更大的数据
- excel - 导出 ms 访问过滤后的表单数据问题?