我正在尝试制作一个Map
类,其中包含将由其他类设置的映射(例如CharacterManager
。
由于内容取决于其他类,因此我希望Map
采用将始终扩展object
的泛型。
例如:
// Map.ts
interface MapCellData {
collides: boolean;
}
class Map<CellData extends object = {}> {
map!: Array<Array<CellData & MapCellData>>;
}
// CharacterManager.ts
interface CharacterManagerCellData {
character: null | Character;
}
// And so on...
通过查看类型Array<Array<CellData & MapCellData>>
,您可以看到我希望2D数组的每个单元都具有由所有其他类定义的所有属性。
但是,问题在于,我现在必须在首次填充map
时提供这些属性。
这不符合我的需要:我不希望我的Map
类知道要添加的其他类。每个类都应负责填充其数据(Map
负责第一次初始化map
,以便其他人可以认为它可用。)
该解决方案对我来说似乎很简单:由于第一次填充地图时未设置CellData
属性,因此我不得不说它们是可选的。当一个类想要使用它时,它需要检查它是否被设置。
根据这种推理,我将Array<Array<CellData & MapCellData>>
更改为Array<Array<Partial<CellData & MapCellData>>>
。 (只需添加Partial
)。
现在是真正的问题:这不起作用,但是没有有关错误的信息,我不知道我做错了什么。
TypeScript仅声明Type '{ collides: true; }' is not assignable to type 'Partial<CellData & MapCellData>'.
这是一个产生错误的完整示例:
interface CharacterManagerCellData {
character: null | string;
}
interface CollisionCellData {
collides: boolean;
}
// Directly using partial without generic works fine
type BasicCellData = Partial<CharacterManagerCellData & CollisionCellData>;
const myCell: BasicCellData = {
collides: true
}
// Using the same pattern with a generic throws a typescript error
function myFunc<CellData extends object = {}>() {
type RealCellData = Partial<CellData & CollisionCellData>;
const cell: RealCellData = {
collides: true
}
}
我正在使用最新版本的TypeScript(3.6.3),并且也会发生此错误in the playground
答案 0 :(得分:2)
Typescript对于错误没有错。您永远不能安全地将具体值分配给泛型类型。考虑以下示例:
<?php include'index.php';?>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Untitled Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="box">
<div class="form_input">
<form method="post" action="">
<input type="text" name="username" placeholder="Enter
Username"><br><br>
<input type="password" name="password" placeholder="Enter
Password"><br>
<br><input type="submit" name="send">
</form>
<?php
if(isset ($_post['send'])){
$object = new login();
$object->insertintotb($_post['username'], $_post['password']);
foreach($object->errors as $error){
echo $error;
}
}
?>
</div>
</div>
</body>
</html>
考虑到传入的类型, myFunc<{ collides: false }>()
应该是collides
而不是false
,但是您可以使用true
对其进行初始化。这显然是错误的。给定true
的通用功能对任何有效。此限制意味着通常无法实例化对象并将其分配给泛型类型的引用(在这种情况下,可以使用空对象,因为T
使得所有类型都是可选的,而与类型Partial
无关)
此约束存在漏洞,例如允许进行赋值,但是对于泛型类型,如果typescript无法确定属性的最终类型是什么,甚至将无法进行简单赋值:
const cell: RealCellData = {}
如果可以接受某些类型会导致类型不一致的类型,则可以使用类型断言:
// this is better
function myFunc<CellData extends CollisionCellData >() {
type RealCellData = Partial<CellData>;
const cell: RealCellData = { //This is still an error
collides: true
}
cell.collides = true; // this is ok beacuse ts knows collide is boolean
}
//this is not ok
function myFunc<CellData extends object >() {
type RealCellData = Partial<CellData & CollisionCellData>;
const cell: RealCellData = { //This is still an error
collides: true
}
cell.collides = true; // this is not ok, beacuse TS does not know if CellData has collides and what it's type may be
}