我使用打字稿和反应钩子制作了一个名为 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
将始终是string
,数据将是一种类型,具体取决于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
,但它不能是我不想要的任何字符串。我希望我只能传递字符串,这是IMapEditorState
中{[k: string]: ICountry}
的关键或ICountry
中的name
。
有什么方法可以创建名为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"
。
然后您可以使用上述CountryName
定义IMapEditorState
:
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};
Typescript 4.1.5:
就我而言,我需要将这种格式的字符串化日期"YYYY-MM-DD"标记为 ISODate,而不仅仅是字符串。我使用了这种方法,我认为如果有效字符串的数量不仅仅是几个,它比这个答案更有效:
interface ISODateDifferentiator extends String {
[key: string]: unknown;
}
export type ISODate = ISODateDifferentiator & string;
export const ValidateIsoDate = (date: string): date is ISODate => {
return date.match(/^d{4}-d{2}-d{2}$/) !== null;
}
执行不安全的任务时,您将获得所需的Type 'string' is not assignable to type 'ISODate'.
,但可以使用 typeguard 函数进行转换。您仍然可以获得字符串方法自动完成。