[英]TypeScript interface mapped property generic type
我正在努力使這項工作
interface ObjectPool<Ids, T> {
pool: {
[K in Ids]: T<K>;
};
};
interface Player<Id> {
id: Id;
}
let playerPool: ObjectPool<0 | 1 | 2, Player>;
以便
playerPool[0].id === 0;
playerPool[1].id === 1;
playerPool[2].id === 2;
// playerPool[3] error
但是 typescript 說我需要一個通用參數在Player
中的let playerPool: ObjectPool<0 | 1 | 2, Player>;
let playerPool: ObjectPool<0 | 1 | 2, Player>;
所以我試着let playerPool: ObjectPool<0 | 1 | 2, Player<_>>;
let playerPool: ObjectPool<0 | 1 | 2, Player<_>>;
但這也行不通
如果您編寫T<K>
,則T
需要是某種特定類型的操作(例如, type T<K> =...
或interface T<K> {...
或class T<K>...
)。 沒有辦法編寫T<K>
,其中T
是泛型類型參數。 這將需要microsoft/TypeScript#1213中要求的所謂的更高種類的類型,而 TypeScript 對此沒有直接支持。
你可以退后一步,試着想一想你想要做什么,以及是否有任何方法可以在不需要更高種類的類型的情況下表示它。 如果您想要的只是ObjectPool<P, T>
擁有P
中的所有屬性鍵,並且對於每個這樣的鍵K
,除了T
指定的其他一些屬性之外,您希望屬性值具有等於K
的id
屬性,那么您可以在定義中分離出id
部分,以便T
只是一個常規類型。 例如:
type ObjectPool<P extends PropertyKey, T> =
{ [K in P]: { id: K } & T };
現在您可以定義Player
而不使其通用:
interface Player {
id: number, // <-- you don't necessarily need this anymore
name: string,
}
現在是一個ObjectPool<0 | 1 | 2, Player>
ObjectPool<0 | 1 | 2, Player>
ObjectPool<0 | 1 | 2, Player>
的行為應符合要求:
function processPlayerPool(playerPool: ObjectPool<0 | 1 | 2, Player>) {
playerPool[0].id === 0;
playerPool[1].id === 1;
playerPool[2].id === 2;
playerPool[2].name;
playerPool[3] // error
}
然后,您可以定義其他類型來代替Player
並使用它們:
interface Wall {
location: string
orientation: string
}
function processSmallWallPool(wallPool: ObjectPool<0 | 1, Wall>) {
wallPool[0].location // okay
wallPool[0].id === 0; // okay
wallPool[1].orientation // okay
wallPool[2] // error
}
您在評論中提到池中有 2,000 個Wall
對象。 這是要放入union的很多元素,但可以肯定的是,您可以做到(代碼生成將比試圖說服編譯器計算它更容易):
// console.log("type WallIds = " + Array.from({ length: 2000 }, (_, i) => i).join(" | "));
type WallIds = 0 | 1 | 2 | 3 | 4 | // ✂ SNIP!
| 1995 | 1996 | 1997 | 1998 | 1999
然后ObjectPool<WallIds, Wall>
也將按需要運行:
function processWallPool(wallPool: ObjectPool<WallIds, Wall>) {
wallPool[214].location
wallPool[100].id // 100
wallPool[1954].orientation
wallPool[2021] // error
}
請注意,盡管編譯器確實無法對數字文字的聯合進行太多分析。 您可能會遇到比您預期的更多的麻煩。 如果您嘗試使用數字索引i
wallPool
的元素,編譯器會報錯:
for (let i = 0; i < 2000; i++) {
wallPool[i] // error!
//~~~~~~~~~~~
// No index signature with a parameter of type 'number'
// was found on type 'ObjectPool<WallIds, Wall>'
}
它不知道i
在該循環中被保證是WallIds
類型的值。 它推斷number
,並且您不能使用任何舊number
索引到wallPool
。 它必須是WallIds
聯合的值。 您可以斷言i
是WallIds
:
for (let i = 0 as WallIds; i < 20000; i++) {
wallPool[i] // no error, but, 20000 is an oopsie
}
但是,如上所示,您會遇到編譯器無法理解i++
可能使i
不再是有效WallIds
的問題,如microsoft/TypeScript#14745的此評論中所述。
如果您只打算使用數字文字值(如wallPool[123]
或wallPool[1987]
)對WallPool
進行索引,那很好。 但是,一旦您開始存儲和操作number
類型的索引,您可能會遇到這種方法的障礙。 它對您來說可能仍然值得,但重要的是要意識到這一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.