javascript - 如何在打字稿中制作字符串的子类型
问题描述
我使用 typescript 和 react hooks 制作了一个名为 risk 的游戏。游戏在某种地图上进行。所以首先我有设计我MapEditor
。地图编辑器的状态就像
export interface IMapEditorState {
mousePos: IPoint;
countries: {[k: string]: ICountry};
continents: { [k: string]: IContinent };
}
countries
并且continents
是对象。国家的界面看起来像
//The "name" property and above key will be same in `{[k: string]: ICountry};` will be same
export interface ICountry {
name: string;
border: IDot[];
neighbours: string[];
completed: boolean;
}
现在我做了一个减速器功能。对于所有类型的动作,我使用了两个道具name
和data
. name
将始终是 astring
并且 data 将是一个类型,具体取决于name
type ActionTypes = {name: "removeCountry", data: string} | {name: "addCountry", data: ICountry};
const reducer = (state: IMapEditorState, action: ActionTypes) => {
...
}
现在看第一个类型ActionTypes
是{name: "removeCountry", data: string}
。在调度方法中,我将使用{name: "removeCountry"}
编译器将强制传递data
为,string
但它不能是我不想要的任何字符串。我希望我应该只能传递作为{[k: string]: ICountry}
inIMapEditorState
或name
inICountry
键的字符串。
有什么方法可以创建一个名为的字符串的子类型CountryName
并使用它
export interface IMapEditorState {
mousePos: IPoint;
countries: {[k: CountryName]: ICountry};
continents: { [k: string]: IContinent };
}
export interface ICountry {
name: CountryName;
border: IDot[];
neighbours: string[];
completed: boolean;
}
type ActionTypes = {name: "removeCountry", data: CountryName} | {name: "addCountry", data: ICountry};
如果你能帮助我,我将非常感激,如果你知道游戏是什么,请给出你对我的数据结构的看法。
解决方案
如果您希望能够在编译时进行这些检查,则必须列出所有可能的国家/地区名称:
type CountryName = 'cName1' | 'cName2' | 'cName3';
或者,如果您可以定义所有可能国家/地区的初始对象,则可以将其声明为const
(以便 TS 不会泛化其字符串),然后通过以下方式获取其键keyof
:
const initialCountries = {
cName1: {
name: 'cName1',
completed: false
// ...
},
cName2: {
name: 'cName2',
completed: false
},
cName3: {
name: 'cName3',
completed: false
},
} as const;
type CountryName = keyof typeof initialCountries;
结果CountryName
是"cName1" | "cName2" | "cName3"
。
然后你可以IMapEditorState
使用上面的定义CountryName
:
export interface ICountry {
name: CountryName;
border: IDot[];
neighbours: string[];
completed: boolean;
}
export interface IMapEditorState {
mousePos: IPoint;
countries: { [k: CountryName]: ICountry };
continents: { [k: string]: IContinent };
}
然后将编译以下内容:
const initalIMapEditorState: IMapEditorState = {
countries: initialCountries,
// ...
};
然后您可以CountryName
在其他任何需要的地方使用:
type ActionTypes = {name: "removeCountry", data: CountryName} | {name: "addCountry", data: ICountry};
推荐阅读
- xamarin.forms - Xamarin Forms:CollectionView 在 ios 中不起作用
- swift - AVFoundation AVAudioSourceNode 格式似乎是一种原生格式,与 AVAudioEngine 的其余部分不同
- javascript - 如何在与模板引擎协同工作的 React DOM Server 中使用 renderToNodeStream?
- typescript - 空的 Promise 拒绝是否需要显式键入为 VOID?
- java - 使用 Spring Boot 进行 Jackson 多态反序列化 JSON解析错误:对象条目内/之间的意外输入结束
- opencart - 网站管理员工具中的opencart 3站点地图提交问题
- hibernate - 使用 Spring Boot 时如何切换数据库
- c# - 如何在 C# 中缓存具有多个键的对象
- php - WooCommerce 在名字字段中强制使用全名
- matplotlib - 在matplotlib中翻转/反转轴标签?