无法在泛型上使用 Partial

Unable to use Partial on a generic type

我正在尝试制作一个 Map class 包含将由其他 class 设置的映射(例如 CharacterManager.
由于内容取决于其他 class,我希望 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>>,您可以看到我希望二维数组的每个单元格都具有所有其他 classes 定义的所有属性。

但是,问题是我现在必须在第一次填充 map 时提供这些属性。
这不符合我的需要:我不想让我的 Map class 知道其他 classes 想要添加什么。每个 class 应该负责填写它的数据(并且 Map 负责第一次初始化 map 以便其他人可以认为它可用。)

解决方案对我来说似乎很简单:由于第一次填充地图时未设置 CellData 属性,我不得不说它们是可选的。而当一个 class 想要使用它时,它需要检查它是否被设置。

按照这个推理,我把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

打字稿说的错误没有错。您永远无法安全地将具体值分配给泛型类型。考虑以下示例:

myFunc<{ collides: false }>()
考虑到传入的类型,

collides 应该是 false 而不是 true,但是你用 true 初始化了它。这显然是错误的。给定 T,通用函数应该对 any 有效。此限制意味着通常不可能实例化对象并将其分配给泛型类型的引用(在这种情况下可以使用空对象,因为 Partial 使所有内容都可选,而不管类型如何 const cell: RealCellData = {}

此约束存在漏洞,例如允许赋值,但对于泛型类型,如果 typescript 无法确定 属性 的最终类型是什么,它甚至不允许简单的赋值:

// 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
}

如果您同意某些类型在您的类型中产生不一致,您可以使用类型断言:

const cell = {
  collides: true
} as RealCellData

Play