无法在泛型上使用 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
我正在尝试制作一个 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